Skip to content

Commit f2c8f5a

Browse files
authored
release(required): Amplify JS release (#13862)
2 parents 4dae76e + a0d1447 commit f2c8f5a

File tree

16 files changed

+424
-374
lines changed

16 files changed

+424
-374
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Identity, ResourcesConfig } from '@aws-amplify/core';
5+
6+
import { DefaultIdentityIdStore } from '../../../../src/providers/cognito/credentialsProvider/IdentityIdStore';
7+
8+
const mockKeyValueStorage = {
9+
setItem: jest.fn(),
10+
getItem: jest.fn(),
11+
removeItem: jest.fn(),
12+
clear: jest.fn(),
13+
};
14+
15+
const validAuthConfig: ResourcesConfig = {
16+
Auth: {
17+
Cognito: {
18+
userPoolId: 'us-east-1_test-id',
19+
identityPoolId: 'us-east-1:test-id',
20+
userPoolClientId: 'test-id',
21+
allowGuestAccess: true,
22+
},
23+
},
24+
};
25+
const validAuthKey = {
26+
identityId: `com.amplify.Cognito.${
27+
validAuthConfig.Auth!.Cognito!.identityPoolId
28+
}.identityId`,
29+
};
30+
const validGuestIdentityId: Identity = { type: 'guest', id: 'guest-id' };
31+
const validPrimaryIdentityId: Identity = { type: 'primary', id: 'primary-id' };
32+
33+
const noIdentityPoolIdAuthConfig: ResourcesConfig = {
34+
Auth: {
35+
Cognito: {
36+
userPoolId: 'us-east-1_test-id',
37+
userPoolClientId: 'test-id',
38+
},
39+
},
40+
};
41+
42+
describe('DefaultIdentityIdStore', () => {
43+
const defaultIdStore = new DefaultIdentityIdStore(mockKeyValueStorage);
44+
beforeAll(() => {
45+
defaultIdStore.setAuthConfig(validAuthConfig.Auth!);
46+
});
47+
48+
afterEach(() => {
49+
mockKeyValueStorage.setItem.mockClear();
50+
mockKeyValueStorage.getItem.mockClear();
51+
mockKeyValueStorage.removeItem.mockClear();
52+
mockKeyValueStorage.clear.mockClear();
53+
});
54+
55+
it('should set the Auth config required to form the storage keys', async () => {
56+
expect(defaultIdStore._authKeys).toEqual(validAuthKey);
57+
});
58+
59+
it('should store guest identityId in keyValueStorage', async () => {
60+
defaultIdStore.storeIdentityId(validGuestIdentityId);
61+
expect(mockKeyValueStorage.setItem).toHaveBeenCalledWith(
62+
validAuthKey.identityId,
63+
validGuestIdentityId.id,
64+
);
65+
expect(defaultIdStore._primaryIdentityId).toBeUndefined();
66+
expect(defaultIdStore._hasGuestIdentityId).toBe(true);
67+
});
68+
69+
it('should load guest identityId from keyValueStorage', async () => {
70+
mockKeyValueStorage.getItem.mockReturnValue(validGuestIdentityId.id);
71+
72+
expect(await defaultIdStore.loadIdentityId()).toEqual(validGuestIdentityId);
73+
});
74+
75+
it('should store primary identityId in keyValueStorage', async () => {
76+
defaultIdStore.storeIdentityId(validPrimaryIdentityId);
77+
expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith(
78+
validAuthKey.identityId,
79+
);
80+
expect(defaultIdStore._primaryIdentityId).toEqual(
81+
validPrimaryIdentityId.id,
82+
);
83+
expect(defaultIdStore._hasGuestIdentityId).toBe(false);
84+
});
85+
86+
it('should load primary identityId from keyValueStorage', async () => {
87+
expect(await defaultIdStore.loadIdentityId()).toEqual(
88+
validPrimaryIdentityId,
89+
);
90+
});
91+
92+
it('should clear the cached identityId', async () => {
93+
defaultIdStore.clearIdentityId();
94+
expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith(
95+
validAuthKey.identityId,
96+
);
97+
expect(defaultIdStore._primaryIdentityId).toBeUndefined();
98+
});
99+
100+
it('should throw when identityPoolId is not present while setting the auth config', async () => {
101+
expect(() => {
102+
defaultIdStore.setAuthConfig(noIdentityPoolIdAuthConfig.Auth!);
103+
}).toThrow('Invalid identity pool id provided.');
104+
});
105+
106+
it('should return null when the underlying keyValueStorage method returns null', async () => {
107+
mockKeyValueStorage.getItem.mockReturnValue(null);
108+
expect(await defaultIdStore.loadIdentityId()).toBeNull();
109+
});
110+
111+
it('should return null when the underlying keyValueStorage method throws', async () => {
112+
mockKeyValueStorage.getItem.mockRejectedValue(new Error('Error'));
113+
expect(await defaultIdStore.loadIdentityId()).toBeNull();
114+
});
115+
116+
it('should not call keyValueStorage.removeItem when there is no guest identityId to clear', async () => {
117+
const refreshIdentityIdStore = new DefaultIdentityIdStore(
118+
mockKeyValueStorage,
119+
);
120+
refreshIdentityIdStore.setAuthConfig(validAuthConfig.Auth!);
121+
122+
refreshIdentityIdStore.storeIdentityId(validPrimaryIdentityId);
123+
expect(mockKeyValueStorage.removeItem).not.toHaveBeenCalled();
124+
});
125+
});

packages/auth/__tests__/providers/cognito/identityIdStore.test.ts

Lines changed: 0 additions & 97 deletions
This file was deleted.

packages/auth/src/providers/cognito/credentialsProvider/IdentityIdStore.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export class DefaultIdentityIdStore implements IdentityIdStore {
2323
// Used as in-memory storage
2424
_primaryIdentityId: string | undefined;
2525
_authKeys: AuthKeys<string> = {};
26+
_hasGuestIdentityId = false;
27+
2628
setAuthConfig(authConfigParam: AuthConfig) {
2729
assertIdentityPoolIdConfig(authConfigParam.Cognito);
2830
this.authConfig = authConfigParam;
@@ -48,7 +50,10 @@ export class DefaultIdentityIdStore implements IdentityIdStore {
4850
const storedIdentityId = await this.keyValueStorage.getItem(
4951
this._authKeys.identityId,
5052
);
53+
5154
if (storedIdentityId) {
55+
this._hasGuestIdentityId = true;
56+
5257
return {
5358
id: storedIdentityId,
5459
type: 'guest',
@@ -71,10 +76,14 @@ export class DefaultIdentityIdStore implements IdentityIdStore {
7176
this.keyValueStorage.setItem(this._authKeys.identityId, identity.id);
7277
// Clear in-memory storage of primary identityId
7378
this._primaryIdentityId = undefined;
79+
this._hasGuestIdentityId = true;
7480
} else {
7581
this._primaryIdentityId = identity.id;
7682
// Clear locally stored guest id
77-
this.keyValueStorage.removeItem(this._authKeys.identityId);
83+
if (this._hasGuestIdentityId) {
84+
this.keyValueStorage.removeItem(this._authKeys.identityId);
85+
this._hasGuestIdentityId = false;
86+
}
7887
}
7988
}
8089

packages/rtn-web-browser/android/src/main/kotlin/com/amazonaws/amplify/rtnwebbrowser/WebBrowserModule.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class WebBrowserModule(
4444
getCustomTabsPackageName(reactApplicationContext)?.let {
4545
val customTabsIntent = CustomTabsIntent.Builder(connection?.getSession()).build()
4646
customTabsIntent.intent.setPackage(it).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
47+
customTabsIntent.intent.setPackage(it).addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
4748
customTabsIntent.launchUrl(reactApplicationContext, Uri.parse(uriStr))
4849
} ?: run {
4950
promise.reject(Throwable("No eligible browser found on device"))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { byteLength } from '../../../../../src/providers/s3/apis/uploadData/byteLength';
5+
6+
describe('byteLength', () => {
7+
it('returns 0 for null or undefined', () => {
8+
expect(byteLength(undefined)).toBe(0);
9+
expect(byteLength(null)).toBe(0);
10+
});
11+
12+
it('calculates byte length correctly for ASCII strings', () => {
13+
expect(byteLength('hello')).toBe(5);
14+
});
15+
16+
it('calculates byte length correctly for multi-byte characters', () => {
17+
expect(byteLength('èちは')).toBe(8);
18+
});
19+
20+
it('handles Uint8Array correctly', () => {
21+
const input = new Uint8Array([1, 2, 3]);
22+
expect(byteLength(input)).toBe(3);
23+
});
24+
25+
it('handles ArrayBuffer correctly', () => {
26+
const buffer = new ArrayBuffer(8);
27+
expect(byteLength(buffer)).toBe(8);
28+
});
29+
30+
it('handles File object correctly', () => {
31+
const file = new Blob(['hello']);
32+
expect(byteLength(file)).toBe(5);
33+
});
34+
35+
it('returns undefined for unsupported types', () => {
36+
const input = { unsupportedType: true };
37+
expect(byteLength(input)).toBeUndefined();
38+
});
39+
});

packages/storage/__tests__/providers/s3/utils/md5.native.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,23 @@ describe('calculateContentMd5 (native)', () => {
6969
mockMd5.mockReset();
7070
});
7171

72-
it('calculates MD5 for content type: string', async () => {
73-
await calculateContentMd5(stringContent);
74-
const [mockMd5Instance] = mockMd5.mock.instances;
75-
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(stringContent);
76-
expect(mockToBase64).toHaveBeenCalled();
77-
});
78-
7972
it.each([
73+
{ type: 'string', content: stringContent },
8074
{ type: 'ArrayBuffer view', content: new Uint8Array() },
8175
{ type: 'ArrayBuffer', content: new ArrayBuffer(8) },
82-
{ type: 'Blob', content: new Blob([stringContent]) },
8376
])('calculates MD5 for content type: $type', async ({ content }) => {
77+
await calculateContentMd5(content);
78+
const [mockMd5Instance] = mockMd5.mock.instances;
79+
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(content);
80+
expect(mockToBase64).toHaveBeenCalled();
81+
});
82+
83+
it('calculates MD5 for content type: blob', async () => {
8484
Object.defineProperty(global, 'FileReader', {
8585
writable: true,
8686
value: jest.fn(() => mockSuccessfulFileReader),
8787
});
88-
await calculateContentMd5(content);
88+
await calculateContentMd5(new Blob([stringContent]));
8989
const [mockMd5Instance] = mockMd5.mock.instances;
9090
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(fileReaderResult);
9191
expect(mockSuccessfulFileReader.readAsArrayBuffer).toHaveBeenCalled();

packages/storage/__tests__/providers/s3/utils/md5.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,23 @@ describe('calculateContentMd5', () => {
4646
mockMd5.mockReset();
4747
});
4848

49-
it('calculates MD5 for content type: string', async () => {
50-
await calculateContentMd5(stringContent);
51-
const [mockMd5Instance] = mockMd5.mock.instances;
52-
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(stringContent);
53-
expect(mockToBase64).toHaveBeenCalled();
54-
});
55-
5649
it.each([
50+
{ type: 'string', content: stringContent },
5751
{ type: 'ArrayBuffer view', content: new Uint8Array() },
5852
{ type: 'ArrayBuffer', content: new ArrayBuffer(8) },
59-
{ type: 'Blob', content: new Blob([stringContent]) },
6053
])('calculates MD5 for content type: $type', async ({ content }) => {
54+
await calculateContentMd5(content);
55+
const [mockMd5Instance] = mockMd5.mock.instances;
56+
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(content);
57+
expect(mockToBase64).toHaveBeenCalled();
58+
});
59+
60+
it('calculates MD5 for content type: blob', async () => {
6161
Object.defineProperty(global, 'FileReader', {
6262
writable: true,
6363
value: jest.fn(() => mockSuccessfulFileReader),
6464
});
65-
await calculateContentMd5(content);
65+
await calculateContentMd5(new Blob([stringContent]));
6666
const [mockMd5Instance] = mockMd5.mock.instances;
6767
expect(mockMd5Instance.update.mock.calls[0][0]).toBe(fileReaderResult);
6868
expect(mockSuccessfulFileReader.readAsArrayBuffer).toHaveBeenCalled();

packages/storage/src/providers/s3/apis/internal/list.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import {
2121
validateStorageOperationInputWithPrefix,
2222
} from '../../utils';
2323
import {
24-
ListAllOptionsWithPath,
25-
ListPaginateOptionsWithPath,
24+
ListAllWithPathOptions,
25+
ListPaginateWithPathOptions,
2626
ResolvedS3Config,
2727
} from '../../types/options';
2828
import {
@@ -267,7 +267,7 @@ const mapCommonPrefixesToExcludedSubpaths = (
267267
};
268268

269269
const getDelimiter = (
270-
options?: ListAllOptionsWithPath | ListPaginateOptionsWithPath,
270+
options?: ListAllWithPathOptions | ListPaginateWithPathOptions,
271271
): string | undefined => {
272272
if (options?.subpathStrategy?.strategy === 'exclude') {
273273
return options?.subpathStrategy?.delimiter ?? DEFAULT_DELIMITER;

0 commit comments

Comments
 (0)