@@ -697,4 +697,140 @@ describe("mjml loader", () => {
697697 expect ( output ) . toMatch ( / C o m i e n c e c o n ( < \/ s p a n > ) ? < s t r o n g > / ) ;
698698 expect ( output ) . not . toContain ( "Comience con<strong>" ) ;
699699 } ) ;
700+
701+ test ( "should handle empty input string in pull" , async ( ) => {
702+ const loader = createMjmlLoader ( ) ;
703+ loader . setDefaultLocale ( "en" ) ;
704+
705+ const result = await loader . pull ( "en" , "" ) ;
706+
707+ expect ( result ) . toEqual ( { } ) ;
708+ } ) ;
709+
710+ test ( "should handle whitespace-only input in pull" , async ( ) => {
711+ const loader = createMjmlLoader ( ) ;
712+ loader . setDefaultLocale ( "en" ) ;
713+
714+ const result = await loader . pull ( "en" , " \n\t " ) ;
715+
716+ expect ( result ) . toEqual ( { } ) ;
717+ } ) ;
718+
719+ test ( "should handle empty input string in push" , async ( ) => {
720+ const loader = createMjmlLoader ( ) ;
721+ loader . setDefaultLocale ( "en" ) ;
722+
723+ // Need to pull first to initialize state
724+ await loader . pull ( "en" , "" ) ;
725+ const output = await loader . push ( "es" , { } , "" ) ;
726+
727+ expect ( output ) . toBe ( "" ) ;
728+ } ) ;
729+
730+ test ( "should handle whitespace-only input in push" , async ( ) => {
731+ const loader = createMjmlLoader ( ) ;
732+ loader . setDefaultLocale ( "en" ) ;
733+
734+ // Need to pull first to initialize state
735+ await loader . pull ( "en" , " \n\t " ) ;
736+ const output = await loader . push ( "es" , { } , " \n\t " ) ;
737+
738+ expect ( output ) . toBe ( " \n\t " ) ;
739+ } ) ;
740+
741+ test ( "should not add XML declaration to output" , async ( ) => {
742+ const loader = createMjmlLoader ( ) ;
743+ loader . setDefaultLocale ( "en" ) ;
744+
745+ const inputWithoutDeclaration = `<mjml>
746+ <mj-body>
747+ <mj-section>
748+ <mj-column>
749+ <mj-text>Hello World</mj-text>
750+ </mj-column>
751+ </mj-section>
752+ </mj-body>
753+ </mjml>` ;
754+
755+ await loader . pull ( "en" , inputWithoutDeclaration ) ;
756+
757+ const translations = {
758+ "mjml/mj-body/0/mj-section/0/mj-column/0/mj-text/0" : "Hola Mundo" ,
759+ } ;
760+
761+ const output = await loader . push ( "es" , translations , inputWithoutDeclaration ) ;
762+
763+ // Should NOT start with XML declaration
764+ expect ( output ) . not . toMatch ( / ^ < \? x m l / ) ;
765+ // Should start with <mjml>
766+ expect ( output . trim ( ) ) . toMatch ( / ^ < m j m l > / ) ;
767+ expect ( output ) . toContain ( "Hola Mundo" ) ;
768+ } ) ;
769+
770+ test ( "should handle input with XML declaration and not duplicate it" , async ( ) => {
771+ const loader = createMjmlLoader ( ) ;
772+ loader . setDefaultLocale ( "en" ) ;
773+
774+ const inputWithDeclaration = `<?xml version="1.0" encoding="UTF-8"?>
775+ <mjml>
776+ <mj-body>
777+ <mj-section>
778+ <mj-column>
779+ <mj-text>Hello World</mj-text>
780+ </mj-column>
781+ </mj-section>
782+ </mj-body>
783+ </mjml>` ;
784+
785+ await loader . pull ( "en" , inputWithDeclaration ) ;
786+
787+ const translations = {
788+ "mjml/mj-body/0/mj-section/0/mj-column/0/mj-text/0" : "Hola Mundo" ,
789+ } ;
790+
791+ const output = await loader . push ( "es" , translations , inputWithDeclaration ) ;
792+
793+ // Should not duplicate XML declaration
794+ const declarationMatches = output . match ( / < \? x m l / g) ;
795+ expect ( declarationMatches ) . toBeNull ( ) ; // No XML declaration in output
796+ expect ( output ) . toContain ( "Hola Mundo" ) ;
797+ } ) ;
798+
799+ test ( "should match structure of source file without XML declaration" , async ( ) => {
800+ const loader = createMjmlLoader ( ) ;
801+ loader . setDefaultLocale ( "en" ) ;
802+
803+ // Source file format (en-US)
804+ const sourceInput = `<mjml>
805+ <mj-body>
806+ <mj-section padding="26px 0px 86px 45px">
807+ <mj-column>
808+ <mj-image
809+ src="cid:logo.png"
810+ alt="GitProtect logo"
811+ width="140px"
812+ height="35px"
813+ padding="0"
814+ align="left"
815+ />
816+ </mj-column>
817+ </mj-section>
818+ </mj-body>
819+ </mjml>` ;
820+
821+ await loader . pull ( "en" , sourceInput ) ;
822+
823+ const translations = {
824+ "mjml/mj-body/0/mj-section/0/mj-column/0/mj-image/0#alt" : "Logo de GitProtect" ,
825+ } ;
826+
827+ const output = await loader . push ( "es" , translations , sourceInput ) ;
828+
829+ // Generated file should match source structure
830+ expect ( output . trim ( ) ) . toMatch ( / ^ < m j m l > / ) ;
831+ expect ( output ) . not . toMatch ( / ^ < \? x m l / ) ;
832+ expect ( output ) . toContain ( "Logo de GitProtect" ) ;
833+ expect ( output ) . toContain ( "<mjml>" ) ;
834+ expect ( output ) . toContain ( "</mjml>" ) ;
835+ } ) ;
700836} ) ;
0 commit comments