Skip to content

Commit 0eedca5

Browse files
authored
Merge pull request #726 from Iterable/jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-classes
[MOB-10946] Update JWT in ts
2 parents 9883a21 + 71ac5c4 commit 0eedca5

File tree

14 files changed

+482
-17
lines changed

14 files changed

+482
-17
lines changed

example/src/hooks/useIterableApp.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
IterableConfig,
1515
IterableInAppShowResponse,
1616
IterableLogLevel,
17+
IterableRetryBackoff,
1718
} from '@iterable/react-native-sdk';
1819

1920
import { Route } from '../constants/routes';
@@ -126,6 +127,16 @@ export const IterableAppProvider: FunctionComponent<
126127

127128
config.inAppDisplayInterval = 1.0; // Min gap between in-apps. No need to set this in production.
128129

130+
config.retryPolicy = {
131+
maxRetry: 5,
132+
retryInterval: 10,
133+
retryBackoff: IterableRetryBackoff.LINEAR,
134+
};
135+
136+
config.onJWTError = (authFailure) => {
137+
console.error('Error fetching JWT:', authFailure);
138+
};
139+
129140
config.urlHandler = (url: string) => {
130141
const routeNames = [Route.Commerce, Route.Inbox, Route.User];
131142
for (const route of routeNames) {

src/__mocks__/MockRNIterableAPI.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@ export class MockRNIterableAPI {
7070

7171
static initialize2WithApiKey = jest.fn().mockResolvedValue(true);
7272

73-
static wakeApp = jest.fn()
73+
static wakeApp = jest.fn();
7474

7575
static setInAppShowResponse = jest.fn();
7676

7777
static passAlongAuthToken = jest.fn();
7878

79+
static pauseAuthRetries = jest.fn();
80+
7981
static async getInAppMessages(): Promise<IterableInAppMessage[] | undefined> {
8082
return await new Promise((resolve) => {
8183
resolve(MockRNIterableAPI.messages);

src/api/NativeRNIterableAPI.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export interface Spec extends TurboModule {
116116

117117
// Auth
118118
passAlongAuthToken(authToken?: string | null): void;
119+
pauseAuthRetries(pauseRetry: boolean): void;
119120

120121
// Wake app -- android only
121122
wakeApp(): void;

src/core/classes/Iterable.test.ts

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,4 +912,261 @@ describe('Iterable', () => {
912912
});
913913
});
914914
});
915+
916+
describe('authManager', () => {
917+
describe('pauseAuthRetries', () => {
918+
it('should call RNIterableAPI.pauseAuthRetries with true when pauseRetry is true', () => {
919+
// GIVEN pauseRetry is true
920+
const pauseRetry = true;
921+
922+
// WHEN pauseAuthRetries is called
923+
Iterable.authManager.pauseAuthRetries(pauseRetry);
924+
925+
// THEN RNIterableAPI.pauseAuthRetries is called with true
926+
expect(MockRNIterableAPI.pauseAuthRetries).toBeCalledWith(true);
927+
});
928+
929+
it('should call RNIterableAPI.pauseAuthRetries with false when pauseRetry is false', () => {
930+
// GIVEN pauseRetry is false
931+
const pauseRetry = false;
932+
933+
// WHEN pauseAuthRetries is called
934+
Iterable.authManager.pauseAuthRetries(pauseRetry);
935+
936+
// THEN RNIterableAPI.pauseAuthRetries is called with false
937+
expect(MockRNIterableAPI.pauseAuthRetries).toBeCalledWith(false);
938+
});
939+
940+
it('should return the result from RNIterableAPI.pauseAuthRetries', () => {
941+
// GIVEN RNIterableAPI.pauseAuthRetries returns a value
942+
const expectedResult = 'pause-result';
943+
MockRNIterableAPI.pauseAuthRetries = jest
944+
.fn()
945+
.mockReturnValue(expectedResult);
946+
947+
// WHEN pauseAuthRetries is called
948+
const result = Iterable.authManager.pauseAuthRetries(true);
949+
950+
// THEN the result is returned
951+
expect(result).toBe(expectedResult);
952+
});
953+
});
954+
955+
describe('passAlongAuthToken', () => {
956+
it('should call RNIterableAPI.passAlongAuthToken with a valid string token', async () => {
957+
// GIVEN a valid auth token
958+
const authToken = 'valid-jwt-token';
959+
const expectedResponse = new IterableAuthResponse();
960+
expectedResponse.authToken = 'new-token';
961+
MockRNIterableAPI.passAlongAuthToken = jest
962+
.fn()
963+
.mockResolvedValue(expectedResponse);
964+
965+
// WHEN passAlongAuthToken is called
966+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
967+
968+
// THEN RNIterableAPI.passAlongAuthToken is called with the token
969+
expect(MockRNIterableAPI.passAlongAuthToken).toBeCalledWith(authToken);
970+
expect(result).toBe(expectedResponse);
971+
});
972+
973+
it('should call RNIterableAPI.passAlongAuthToken with null token', async () => {
974+
// GIVEN a null auth token
975+
const authToken = null;
976+
const expectedResponse = 'success';
977+
MockRNIterableAPI.passAlongAuthToken = jest
978+
.fn()
979+
.mockResolvedValue(expectedResponse);
980+
981+
// WHEN passAlongAuthToken is called
982+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
983+
984+
// THEN RNIterableAPI.passAlongAuthToken is called with null
985+
expect(MockRNIterableAPI.passAlongAuthToken).toBeCalledWith(null);
986+
expect(result).toBe(expectedResponse);
987+
});
988+
989+
it('should call RNIterableAPI.passAlongAuthToken with undefined token', async () => {
990+
// GIVEN an undefined auth token
991+
const authToken = undefined;
992+
const expectedResponse = undefined;
993+
MockRNIterableAPI.passAlongAuthToken = jest
994+
.fn()
995+
.mockResolvedValue(expectedResponse);
996+
997+
// WHEN passAlongAuthToken is called
998+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
999+
1000+
// THEN RNIterableAPI.passAlongAuthToken is called with undefined
1001+
expect(MockRNIterableAPI.passAlongAuthToken).toBeCalledWith(undefined);
1002+
expect(result).toBe(expectedResponse);
1003+
});
1004+
1005+
it('should call RNIterableAPI.passAlongAuthToken with empty string token', async () => {
1006+
// GIVEN an empty string auth token
1007+
const authToken = '';
1008+
const expectedResponse = new IterableAuthResponse();
1009+
MockRNIterableAPI.passAlongAuthToken = jest
1010+
.fn()
1011+
.mockResolvedValue(expectedResponse);
1012+
1013+
// WHEN passAlongAuthToken is called
1014+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
1015+
1016+
// THEN RNIterableAPI.passAlongAuthToken is called with empty string
1017+
expect(MockRNIterableAPI.passAlongAuthToken).toBeCalledWith('');
1018+
expect(result).toBe(expectedResponse);
1019+
});
1020+
1021+
it('should return IterableAuthResponse when API returns IterableAuthResponse', async () => {
1022+
// GIVEN API returns IterableAuthResponse
1023+
const authToken = 'test-token';
1024+
const expectedResponse = new IterableAuthResponse();
1025+
expectedResponse.authToken = 'new-token';
1026+
expectedResponse.successCallback = jest.fn();
1027+
expectedResponse.failureCallback = jest.fn();
1028+
MockRNIterableAPI.passAlongAuthToken = jest
1029+
.fn()
1030+
.mockResolvedValue(expectedResponse);
1031+
1032+
// WHEN passAlongAuthToken is called
1033+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
1034+
1035+
// THEN the result is the expected IterableAuthResponse
1036+
expect(result).toBe(expectedResponse);
1037+
expect(result).toBeInstanceOf(IterableAuthResponse);
1038+
});
1039+
1040+
it('should return string when API returns string', async () => {
1041+
// GIVEN API returns string
1042+
const authToken = 'test-token';
1043+
const expectedResponse = 'success-string';
1044+
MockRNIterableAPI.passAlongAuthToken = jest
1045+
.fn()
1046+
.mockResolvedValue(expectedResponse);
1047+
1048+
// WHEN passAlongAuthToken is called
1049+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
1050+
1051+
// THEN the result is the expected string
1052+
expect(result).toBe(expectedResponse);
1053+
expect(typeof result).toBe('string');
1054+
});
1055+
1056+
it('should return undefined when API returns undefined', async () => {
1057+
// GIVEN API returns undefined
1058+
const authToken = 'test-token';
1059+
const expectedResponse = undefined;
1060+
MockRNIterableAPI.passAlongAuthToken = jest
1061+
.fn()
1062+
.mockResolvedValue(expectedResponse);
1063+
1064+
// WHEN passAlongAuthToken is called
1065+
const result = await Iterable.authManager.passAlongAuthToken(authToken);
1066+
1067+
// THEN the result is undefined
1068+
expect(result).toBeUndefined();
1069+
});
1070+
1071+
it('should handle API rejection and propagate the error', async () => {
1072+
// GIVEN API rejects with an error
1073+
const authToken = 'test-token';
1074+
const expectedError = new Error('API Error');
1075+
MockRNIterableAPI.passAlongAuthToken = jest
1076+
.fn()
1077+
.mockRejectedValue(expectedError);
1078+
1079+
// WHEN passAlongAuthToken is called
1080+
// THEN the error is propagated
1081+
await expect(
1082+
Iterable.authManager.passAlongAuthToken(authToken)
1083+
).rejects.toThrow('API Error');
1084+
});
1085+
1086+
it('should handle API rejection with network error', async () => {
1087+
// GIVEN API rejects with a network error
1088+
const authToken = 'test-token';
1089+
const networkError = new Error('Network request failed');
1090+
MockRNIterableAPI.passAlongAuthToken = jest
1091+
.fn()
1092+
.mockRejectedValue(networkError);
1093+
1094+
// WHEN passAlongAuthToken is called
1095+
// THEN the network error is propagated
1096+
await expect(
1097+
Iterable.authManager.passAlongAuthToken(authToken)
1098+
).rejects.toThrow('Network request failed');
1099+
});
1100+
1101+
it('should handle API rejection with timeout error', async () => {
1102+
// GIVEN API rejects with a timeout error
1103+
const authToken = 'test-token';
1104+
const timeoutError = new Error('Request timeout');
1105+
MockRNIterableAPI.passAlongAuthToken = jest
1106+
.fn()
1107+
.mockRejectedValue(timeoutError);
1108+
1109+
// WHEN passAlongAuthToken is called
1110+
// THEN the timeout error is propagated
1111+
await expect(
1112+
Iterable.authManager.passAlongAuthToken(authToken)
1113+
).rejects.toThrow('Request timeout');
1114+
});
1115+
});
1116+
1117+
describe('integration', () => {
1118+
it('should work with both methods in sequence', async () => {
1119+
// GIVEN a sequence of operations
1120+
const authToken = 'test-token';
1121+
const expectedResponse = new IterableAuthResponse();
1122+
MockRNIterableAPI.pauseAuthRetries = jest
1123+
.fn()
1124+
.mockReturnValue('paused');
1125+
MockRNIterableAPI.passAlongAuthToken = jest
1126+
.fn()
1127+
.mockResolvedValue(expectedResponse);
1128+
1129+
// WHEN calling both methods in sequence
1130+
const pauseResult = Iterable.authManager.pauseAuthRetries(true);
1131+
const tokenResult =
1132+
await Iterable.authManager.passAlongAuthToken(authToken);
1133+
1134+
// THEN both operations should work correctly
1135+
expect(pauseResult).toBe('paused');
1136+
expect(tokenResult).toBe(expectedResponse);
1137+
expect(MockRNIterableAPI.pauseAuthRetries).toBeCalledWith(true);
1138+
expect(MockRNIterableAPI.passAlongAuthToken).toBeCalledWith(authToken);
1139+
});
1140+
1141+
it('should handle rapid successive calls', async () => {
1142+
// GIVEN rapid successive calls
1143+
const authToken1 = 'token1';
1144+
const authToken2 = 'token2';
1145+
const response1 = new IterableAuthResponse();
1146+
const response2 = 'success';
1147+
MockRNIterableAPI.passAlongAuthToken = jest
1148+
.fn()
1149+
.mockResolvedValueOnce(response1)
1150+
.mockResolvedValueOnce(response2);
1151+
1152+
// WHEN making rapid successive calls
1153+
const promise1 = Iterable.authManager.passAlongAuthToken(authToken1);
1154+
const promise2 = Iterable.authManager.passAlongAuthToken(authToken2);
1155+
const [result1, result2] = await Promise.all([promise1, promise2]);
1156+
1157+
// THEN both calls should work correctly
1158+
expect(result1).toBe(response1);
1159+
expect(result2).toBe(response2);
1160+
expect(MockRNIterableAPI.passAlongAuthToken).toHaveBeenCalledTimes(2);
1161+
expect(MockRNIterableAPI.passAlongAuthToken).toHaveBeenNthCalledWith(
1162+
1,
1163+
authToken1
1164+
);
1165+
expect(MockRNIterableAPI.passAlongAuthToken).toHaveBeenNthCalledWith(
1166+
2,
1167+
authToken2
1168+
);
1169+
});
1170+
});
1171+
});
9151172
});

0 commit comments

Comments
 (0)