@@ -7,6 +7,7 @@ import { Amplify, StorageAccessLevel } from '@aws-amplify/core';
77import { getUrl } from '../../../../../src/providers/s3/apis/internal/getUrl' ;
88import {
99 getPresignedGetObjectUrl ,
10+ getPresignedPutObjectUrl ,
1011 headObject ,
1112} from '../../../../../src/providers/s3/utils/client/s3data' ;
1213import {
@@ -79,6 +80,7 @@ describe('getUrl test with key', () => {
7980 $metadata : { } as any ,
8081 } ) ;
8182 jest . mocked ( getPresignedGetObjectUrl ) . mockResolvedValue ( mockURL ) ;
83+ jest . mocked ( getPresignedPutObjectUrl ) . mockResolvedValue ( mockURL ) ;
8284 } ) ;
8385 afterEach ( ( ) => {
8486 jest . clearAllMocks ( ) ;
@@ -225,6 +227,87 @@ describe('getUrl test with key', () => {
225227 ) ;
226228 } ) ;
227229 } ) ;
230+
231+ describe ( 'method PUT for presigned upload URLs' , ( ) => {
232+ it ( 'should generate PUT presigned URL and skip validation' , async ( ) => {
233+ await getUrlWrapper ( {
234+ key : 'key' ,
235+ options : {
236+ method : 'PUT' ,
237+ validateObjectExistence : true ,
238+ } ,
239+ } ) ;
240+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
241+ expect ( headObject ) . not . toHaveBeenCalled ( ) ;
242+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
243+ {
244+ credentials,
245+ region,
246+ expiration : expect . any ( Number ) ,
247+ } ,
248+ {
249+ Bucket : bucket ,
250+ Key : 'public/key' ,
251+ } ,
252+ ) ;
253+ } ) ;
254+
255+ it ( 'should include content type and disposition for PUT' , async ( ) => {
256+ const contentType = 'image/jpeg' ;
257+ const contentDisposition = 'attachment; filename="test.jpg"' ;
258+ const cacheControl = 'max-age=3600' ;
259+ await getUrlWrapper ( {
260+ key : 'key' ,
261+ options : {
262+ method : 'PUT' ,
263+ contentType,
264+ contentDisposition,
265+ cacheControl,
266+ } ,
267+ } ) ;
268+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
269+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
270+ {
271+ credentials,
272+ region,
273+ expiration : expect . any ( Number ) ,
274+ } ,
275+ {
276+ Bucket : bucket ,
277+ Key : 'public/key' ,
278+ ContentType : contentType ,
279+ ContentDisposition : contentDisposition ,
280+ CacheControl : cacheControl ,
281+ } ,
282+ ) ;
283+ } ) ;
284+
285+ it ( 'should handle object content disposition for PUT' , async ( ) => {
286+ await getUrlWrapper ( {
287+ key : 'key' ,
288+ options : {
289+ method : 'PUT' ,
290+ contentDisposition : {
291+ type : 'attachment' ,
292+ filename : 'test.pdf' ,
293+ } ,
294+ } ,
295+ } ) ;
296+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
297+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
298+ {
299+ credentials,
300+ region,
301+ expiration : expect . any ( Number ) ,
302+ } ,
303+ {
304+ Bucket : bucket ,
305+ Key : 'public/key' ,
306+ ContentDisposition : 'attachment; filename="test.pdf"' ,
307+ } ,
308+ ) ;
309+ } ) ;
310+ } ) ;
228311 } ) ;
229312 describe ( 'Error cases : With key' , ( ) => {
230313 afterAll ( ( ) => {
@@ -285,6 +368,7 @@ describe('getUrl test with path', () => {
285368 $metadata : { } as any ,
286369 } ) ;
287370 jest . mocked ( getPresignedGetObjectUrl ) . mockResolvedValue ( mockURL ) ;
371+ jest . mocked ( getPresignedPutObjectUrl ) . mockResolvedValue ( mockURL ) ;
288372 } ) ;
289373 afterEach ( ( ) => {
290374 jest . clearAllMocks ( ) ;
@@ -418,6 +502,56 @@ describe('getUrl test with path', () => {
418502 ) ;
419503 } ) ;
420504 } ) ;
505+
506+ describe ( 'method PUT for presigned upload URLs with path' , ( ) => {
507+ it ( 'should generate PUT presigned URL with path and skip validation' , async ( ) => {
508+ const inputPath = 'uploads/file.jpg' ;
509+ await getUrlWrapper ( {
510+ path : inputPath ,
511+ options : {
512+ method : 'PUT' ,
513+ validateObjectExistence : true ,
514+ } ,
515+ } ) ;
516+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
517+ expect ( headObject ) . not . toHaveBeenCalled ( ) ;
518+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
519+ {
520+ credentials,
521+ region,
522+ expiration : expect . any ( Number ) ,
523+ } ,
524+ {
525+ Bucket : bucket ,
526+ Key : inputPath ,
527+ } ,
528+ ) ;
529+ } ) ;
530+
531+ it ( 'should include expectedBucketOwner for PUT with path' , async ( ) => {
532+ const inputPath = 'uploads/file.jpg' ;
533+ await getUrlWrapper ( {
534+ path : inputPath ,
535+ options : {
536+ method : 'PUT' ,
537+ expectedBucketOwner : validBucketOwner ,
538+ } ,
539+ } ) ;
540+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
541+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
542+ {
543+ credentials,
544+ region,
545+ expiration : expect . any ( Number ) ,
546+ } ,
547+ {
548+ Bucket : bucket ,
549+ Key : inputPath ,
550+ ExpectedBucketOwner : validBucketOwner ,
551+ } ,
552+ ) ;
553+ } ) ;
554+ } ) ;
421555 } ) ;
422556 describe ( 'Happy cases: With path and Content Disposition, Content Type' , ( ) => {
423557 const config = {
@@ -435,6 +569,7 @@ describe('getUrl test with path', () => {
435569 $metadata : { } as any ,
436570 } ) ;
437571 jest . mocked ( getPresignedGetObjectUrl ) . mockResolvedValue ( mockURL ) ;
572+ jest . mocked ( getPresignedPutObjectUrl ) . mockResolvedValue ( mockURL ) ;
438573 } ) ;
439574 afterEach ( ( ) => {
440575 jest . clearAllMocks ( ) ;
@@ -500,6 +635,7 @@ describe('getUrl test with path', () => {
500635 $metadata : { } as any ,
501636 } ) ;
502637 jest . mocked ( getPresignedGetObjectUrl ) . mockResolvedValue ( mockURL ) ;
638+ jest . mocked ( getPresignedPutObjectUrl ) . mockResolvedValue ( mockURL ) ;
503639 } ) ;
504640
505641 afterEach ( ( ) => {
@@ -660,4 +796,30 @@ describe(`getURL with path and Expected Bucket Owner`, () => {
660796
661797 expect ( getPresignedGetObjectUrl ) . not . toHaveBeenCalled ( ) ;
662798 } ) ;
799+
800+ it ( 'should pass expectedBucketOwner to getPresignedPutObjectUrl for PUT method' , async ( ) => {
801+ const path = 'public/expectedbucketowner_test' ;
802+
803+ await getUrlWrapper ( {
804+ path,
805+ options : {
806+ method : 'PUT' ,
807+ expectedBucketOwner : validBucketOwner ,
808+ } ,
809+ } ) ;
810+
811+ expect ( getPresignedPutObjectUrl ) . toHaveBeenCalledTimes ( 1 ) ;
812+ await expect ( getPresignedPutObjectUrl ) . toBeLastCalledWithConfigAndInput (
813+ {
814+ credentials,
815+ region,
816+ expiration : expect . any ( Number ) ,
817+ } ,
818+ {
819+ Bucket : bucket ,
820+ ExpectedBucketOwner : validBucketOwner ,
821+ Key : path ,
822+ } ,
823+ ) ;
824+ } ) ;
663825} ) ;
0 commit comments