@@ -911,6 +911,132 @@ describe('Product HTML Pipe Test', () => {
911911 fetchMock . unmockGlobal ( ) ;
912912 } ) ;
913913
914+ it ( 'returns 301 when edge content returns a redirect' , async ( ) => {
915+ fetchMock . unmockGlobal ( ) ;
916+ fetchMock . removeRoutes ( ) ;
917+ const fetchMockGlobal = fetchMock . mockGlobal ( ) ;
918+
919+ fetchMockGlobal . get ( 'https://main--site--org.aem.live/products/old-product-url' , {
920+ status : 301 ,
921+ headers : { location : '/products/new-product-url' } ,
922+ } ) ;
923+
924+ const s3Loader = new FileS3Loader ( ) ;
925+ const state = DEFAULT_STATE ( DEFAULT_CONFIG , {
926+ log : console ,
927+ s3Loader,
928+ ref : 'main' ,
929+ path : '/products/old-product-url' ,
930+ partition : 'live' ,
931+ timer : { update : ( ) => { } } ,
932+ } ) ;
933+ state . info = getPathInfo ( '/products/old-product-url' ) ;
934+
935+ const resp = await productHTMLPipe (
936+ state ,
937+ new PipelineRequest ( new URL ( 'https://acme.com/products/old-product-url' ) ) ,
938+ ) ;
939+
940+ assert . strictEqual ( resp . status , 301 ) ;
941+ assert . strictEqual ( resp . headers . get ( 'location' ) , '/products/new-product-url' ) ;
942+ assert . strictEqual ( resp . body , '' ) ;
943+ fetchMock . unmockGlobal ( ) ;
944+ } ) ;
945+
946+ it ( 'returns 301 redirect even when product data also exists in R2' , async ( ) => {
947+ fetchMock . unmockGlobal ( ) ;
948+ fetchMock . removeRoutes ( ) ;
949+ const fetchMockGlobal = fetchMock . mockGlobal ( ) ;
950+
951+ fetchMockGlobal . get ( 'https://main--site--org.aem.live/products/product-simple' , {
952+ status : 301 ,
953+ headers : { location : '/products/new-url' } ,
954+ } ) ;
955+
956+ const s3Loader = new FileS3Loader ( ) ;
957+ const state = DEFAULT_STATE ( DEFAULT_CONFIG , {
958+ log : console ,
959+ s3Loader,
960+ ref : 'main' ,
961+ path : '/products/product-simple' ,
962+ partition : 'live' ,
963+ timer : { update : ( ) => { } } ,
964+ } ) ;
965+ state . info = getPathInfo ( '/products/product-simple' ) ;
966+
967+ const resp = await productHTMLPipe (
968+ state ,
969+ new PipelineRequest ( new URL ( 'https://acme.com/products/product-simple' ) ) ,
970+ ) ;
971+
972+ assert . strictEqual ( resp . status , 301 ) ;
973+ assert . strictEqual ( resp . headers . get ( 'location' ) , '/products/new-url' ) ;
974+ fetchMock . unmockGlobal ( ) ;
975+ } ) ;
976+
977+ it ( 'returns 301 redirect when product is also a 404 in R2' , async ( ) => {
978+ fetchMock . unmockGlobal ( ) ;
979+ fetchMock . removeRoutes ( ) ;
980+ const fetchMockGlobal = fetchMock . mockGlobal ( ) ;
981+
982+ fetchMockGlobal . get ( 'https://main--site--org.aem.live/products/product-404' , {
983+ status : 301 ,
984+ headers : { location : '/products/replacement' } ,
985+ } ) ;
986+
987+ const s3Loader = new FileS3Loader ( ) ;
988+ const state = DEFAULT_STATE ( DEFAULT_CONFIG , {
989+ log : console ,
990+ s3Loader,
991+ ref : 'main' ,
992+ path : '/products/product-404' ,
993+ partition : 'live' ,
994+ timer : { update : ( ) => { } } ,
995+ } ) ;
996+ state . info = getPathInfo ( '/products/product-404' ) ;
997+
998+ const resp = await productHTMLPipe (
999+ state ,
1000+ new PipelineRequest ( new URL ( 'https://acme.com/products/product-404' ) ) ,
1001+ ) ;
1002+
1003+ assert . strictEqual ( resp . status , 301 ) ;
1004+ assert . strictEqual ( resp . headers . get ( 'location' ) , '/products/replacement' ) ;
1005+ fetchMock . unmockGlobal ( ) ;
1006+ } ) ;
1007+
1008+ it ( 'ignores 301 from edge content when location header is missing' , async ( ) => {
1009+ fetchMock . unmockGlobal ( ) ;
1010+ fetchMock . removeRoutes ( ) ;
1011+ const fetchMockGlobal = fetchMock . mockGlobal ( ) ;
1012+
1013+ fetchMockGlobal . get ( 'https://main--site--org.aem.live/products/product-simple' , {
1014+ status : 301 ,
1015+ headers : { } ,
1016+ } ) ;
1017+
1018+ const s3Loader = new FileS3Loader ( ) ;
1019+ const state = DEFAULT_STATE ( DEFAULT_CONFIG , {
1020+ log : console ,
1021+ s3Loader,
1022+ ref : 'main' ,
1023+ path : '/products/product-simple' ,
1024+ partition : 'live' ,
1025+ timer : { update : ( ) => { } } ,
1026+ } ) ;
1027+ state . info = getPathInfo ( '/products/product-simple' ) ;
1028+
1029+ const resp = await productHTMLPipe (
1030+ state ,
1031+ new PipelineRequest ( new URL ( 'https://acme.com/products/product-simple' ) ) ,
1032+ ) ;
1033+
1034+ // No location → redirect is ignored, product renders normally
1035+ assert . strictEqual ( resp . status , 200 ) ;
1036+ assert . ok ( resp . body . includes ( '<h1 id="blitzmax-5000">BlitzMax 5000</h1>' ) ) ;
1037+ fetchMock . unmockGlobal ( ) ;
1038+ } ) ;
1039+
9141040 it ( 'handles authored content with meta tags without name value' , async ( ) => {
9151041 // Clear any existing mocks and set up fresh
9161042 fetchMock . unmockGlobal ( ) ;
0 commit comments