Skip to content

Commit e5a107f

Browse files
committed
use async store pattern instead of sync
1 parent 5f6c8f9 commit e5a107f

File tree

9 files changed

+91
-93
lines changed

9 files changed

+91
-93
lines changed

src/methods/send/send.spec.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,21 @@ jest.mock('../../api/sendPost', () => ({
1515

1616
describe('sdk v3', () => {
1717
it('should call the send method and fail on the public key', () => {
18-
expect(() => send('default_service', 'my_test_template')).toThrow('The public key is required');
18+
send('default_service', 'my_test_template').catch((error) => {
19+
expect(error).toMatch('The public key is required');
20+
});
1921
});
2022

2123
it('should call the send method and fail on the service ID', () => {
22-
expect(() => send('', 'my_test_template', {}, 'C2JWGTestKeySomething')).toThrow(
23-
'The service ID is required',
24-
);
24+
send('', 'my_test_template', {}, 'C2JWGTestKeySomething').catch((error) => {
25+
expect(error).toMatch('The service ID is required');
26+
});
2527
});
2628

2729
it('should call the send method and fail on the template ID', () => {
28-
expect(() => send('default_service', '', {}, 'C2JWGTestKeySomething')).toThrow(
29-
'The template ID is required',
30-
);
30+
send('default_service', '', {}, 'C2JWGTestKeySomething').catch((error) => {
31+
expect(error).toMatch('The template ID is required');
32+
});
3133
});
3234

3335
it('should call the send method successfully with 4 params', async () => {
@@ -42,25 +44,25 @@ describe('sdk v3', () => {
4244

4345
describe('sdk v4', () => {
4446
it('should call the send method and fail on the public key', () => {
45-
expect(() => send('default_service', 'my_test_template', {}, {})).toThrow(
46-
'The public key is required',
47-
);
47+
send('default_service', 'my_test_template', {}, {}).catch((error) => {
48+
expect(error).toMatch('The public key is required');
49+
});
4850
});
4951

5052
it('should call the send method and fail on the service ID', () => {
51-
expect(() =>
52-
send('', 'my_test_template', undefined, {
53-
publicKey: 'C2JWGTestKeySomething',
54-
}),
55-
).toThrow('The service ID is required');
53+
send('', 'my_test_template', undefined, {
54+
publicKey: 'C2JWGTestKeySomething',
55+
}).catch((error) => {
56+
expect(error).toMatch('The service ID is required');
57+
});
5658
});
5759

5860
it('should call the send method and fail on the template ID', () => {
59-
expect(() =>
60-
send('default_service', '', undefined, {
61-
publicKey: 'C2JWGTestKeySomething',
62-
}),
63-
).toThrow('The template ID is required');
61+
send('default_service', '', undefined, {
62+
publicKey: 'C2JWGTestKeySomething',
63+
}).catch((error) => {
64+
expect(error).toMatch('The template ID is required');
65+
});
6466
});
6567

6668
it('should call the send method and fail on headless', async () => {

src/methods/send/send.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { limitRateError } from '../../errors/limitRateError/limitRateError';
2121
* @param {object} options - the EmailJS SDK config options
2222
* @returns {Promise<EmailJSResponseStatus>}
2323
*/
24-
export const send = (
24+
export const send = async (
2525
serviceID: string,
2626
templateID: string,
2727
templateParams?: Record<string, unknown>,
@@ -45,7 +45,7 @@ export const send = (
4545
return Promise.reject(blockedEmailError());
4646
}
4747

48-
if (isLimitRateHit(location.pathname, limitRate, storageProvider)) {
48+
if (await isLimitRateHit(location.pathname, limitRate, storageProvider)) {
4949
return Promise.reject(limitRateError());
5050
}
5151

src/methods/sendForm/sendForm.spec.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ jest.mock('../../api/sendPost', () => ({
1515

1616
describe('sdk v3', () => {
1717
it('should call the sendForm method and fail on the public key', () => {
18-
expect(() => sendForm('default_service', 'my_test_template', '#form-id')).toThrow(
19-
'The public key is required',
20-
);
18+
sendForm('default_service', 'my_test_template', '#form-id').catch((error) => {
19+
expect(error).toMatch('The public key is required');
20+
});
2121
});
2222

2323
it('should call the sendForm method and fail on the service ID', () => {
24-
expect(() => sendForm('', 'my_test_template', '#form-id', 'C2JWGTestKeySomething')).toThrow(
25-
'The service ID is required',
26-
);
24+
sendForm('', 'my_test_template', '#form-id', 'C2JWGTestKeySomething').catch((error) => {
25+
expect(error).toMatch('The service ID is required');
26+
});
2727
});
2828

2929
it('should call the sendForm method and fail on the template ID', () => {
30-
expect(() => sendForm('default_service', '', '#form-id', 'C2JWGTestKeySomething')).toThrow(
31-
'The template ID is required',
32-
);
30+
sendForm('default_service', '', '#form-id', 'C2JWGTestKeySomething').catch((error) => {
31+
expect(error).toMatch('The template ID is required');
32+
});
3333
});
3434

3535
it('should call the sendForm with id selector', async () => {
@@ -69,25 +69,25 @@ describe('sdk v3', () => {
6969

7070
describe('sdk v4', () => {
7171
it('should call the sendForm method and fail on the public key', () => {
72-
expect(() => sendForm('default_service', 'my_test_template', '#form-id')).toThrow(
73-
'The public key is required',
74-
);
72+
sendForm('default_service', 'my_test_template', '#form-id').catch((error) => {
73+
expect(error).toMatch('The public key is required');
74+
});
7575
});
7676

7777
it('should call the sendForm method and fail on the service ID', () => {
78-
expect(() =>
79-
sendForm('', 'my_test_template', '#form-id', {
80-
publicKey: 'C2JWGTestKeySomething',
81-
}),
82-
).toThrow('The service ID is required');
78+
sendForm('', 'my_test_template', '#form-id', {
79+
publicKey: 'C2JWGTestKeySomething',
80+
}).catch((error) => {
81+
expect(error).toMatch('The service ID is required');
82+
});
8383
});
8484

8585
it('should call the sendForm method and fail on the template ID', () => {
86-
expect(() =>
87-
sendForm('default_service', '', '#form-id', {
88-
publicKey: 'C2JWGTestKeySomething',
89-
}),
90-
).toThrow('The template ID is required');
86+
sendForm('default_service', '', '#form-id', {
87+
publicKey: 'C2JWGTestKeySomething',
88+
}).catch((error) => {
89+
expect(error).toMatch('The template ID is required');
90+
});
9191
});
9292

9393
it('should call the sendForm and fail on headless', async () => {

src/methods/sendForm/sendForm.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const findHTMLForm = (form: string | HTMLFormElement): HTMLFormElement | null =>
2525
* @param {object} options - the EmailJS SDK config options
2626
* @returns {Promise<EmailJSResponseStatus>}
2727
*/
28-
export const sendForm = (
28+
export const sendForm = async (
2929
serviceID: string,
3030
templateID: string,
3131
form: string | HTMLFormElement,
@@ -53,7 +53,7 @@ export const sendForm = (
5353
return Promise.reject(blockedEmailError());
5454
}
5555

56-
if (isLimitRateHit(location.pathname, limitRate, storageProvider)) {
56+
if (await isLimitRateHit(location.pathname, limitRate, storageProvider)) {
5757
return Promise.reject(limitRateError());
5858
}
5959

src/types/StorageProvider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export interface StorageProvider {
2-
get: (key: string) => string | null | undefined;
3-
set: (key: string, value: string) => void;
4-
remove: (key: string) => void;
2+
get: (key: string) => Promise<string | null | undefined>;
3+
set: (key: string, value: string) => Promise<void>;
4+
remove: (key: string) => Promise<void>;
55
}

src/utils/createWebStorage/createWebStorage.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ import type { StorageProvider } from '../../types/StorageProvider';
44

55
let storage: StorageProvider;
66

7-
beforeAll(() => {
7+
beforeAll(async () => {
88
storage = createWebStorage()!;
9-
storage.set('test', 'foo');
9+
await storage.set('test', 'foo');
1010
});
1111

12-
it('get value', () => {
13-
expect(storage.get('test')).toEqual('foo');
12+
it('get value', async () => {
13+
expect(await storage.get('test')).toEqual('foo');
1414
});
1515

16-
it('remove value', () => {
17-
storage.remove('test');
18-
expect(storage.get('test')).toEqual(null);
16+
it('remove value', async () => {
17+
await storage.remove('test');
18+
expect(await storage.get('test')).toEqual(null);
1919
});
2020

2121
it('localStorage is not defined', () => {

src/utils/createWebStorage/createWebStorage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ export const createWebStorage = (): StorageProvider | undefined => {
44
if (typeof localStorage === 'undefined') return;
55

66
return {
7-
get: (key) => localStorage.getItem(key),
8-
set: (key, value) => localStorage.setItem(key, value),
9-
remove: (key) => localStorage.removeItem(key),
7+
get: (key) => Promise.resolve(localStorage.getItem(key)),
8+
set: (key, value) => Promise.resolve(localStorage.setItem(key, value)),
9+
remove: (key) => Promise.resolve(localStorage.removeItem(key)),
1010
};
1111
};

src/utils/isLimitRateHit/isLimitRateHit.spec.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,27 @@ beforeEach(() => {
1515
});
1616

1717
describe('limit rate is disabed', () => {
18-
it('empty limit rate options', () => {
18+
it('empty limit rate options', async () => {
1919
const limitRate: LimitRate = {};
2020

21-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
21+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
2222
});
2323

24-
it('throttle is 0', () => {
24+
it('throttle is 0', async () => {
2525
const limitRate: LimitRate = {
2626
throttle: 0,
2727
};
2828

29-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
29+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
3030
});
3131

32-
it('no record', () => {
32+
it('no record', async () => {
3333
const limitRate: LimitRate = {
3434
id: 'app',
3535
throttle: 1000,
3636
};
3737

38-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
38+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
3939
});
4040

4141
it('no hit limit', async () => {
@@ -44,59 +44,59 @@ describe('limit rate is disabed', () => {
4444
throttle: 100,
4545
};
4646

47-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
47+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
4848

4949
await new Promise((r) => setTimeout(r, 150));
5050

51-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
51+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
5252
});
5353

54-
it('not same page or ID', () => {
54+
it('not same page or ID', async () => {
5555
const limitRate: LimitRate = {
5656
throttle: 100,
5757
};
5858

59-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
59+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
6060

6161
location.replace('/new-form');
6262

63-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
63+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
6464
});
6565
});
6666

6767
describe('limit rate is enabled', () => {
68-
it('hit limit', () => {
68+
it('hit limit', async () => {
6969
const limitRate: LimitRate = {
7070
id: 'app',
7171
throttle: 100,
7272
};
7373

74-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
75-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
74+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
75+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
7676
});
7777

78-
it('restore after page refresh and hit limit', () => {
78+
it('restore after page refresh and hit limit', async () => {
7979
const limitRate: LimitRate = {
8080
throttle: 100,
8181
};
8282

83-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
83+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
8484

8585
location.reload();
8686

87-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
87+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
8888
});
8989

90-
it('next page refresh and hit limit', () => {
90+
it('next page refresh and hit limit', async () => {
9191
const limitRate: LimitRate = {
9292
id: 'app',
9393
throttle: 100,
9494
};
9595

96-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
96+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeFalsy();
9797

9898
location.replace('/new-form');
9999

100-
expect(isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
100+
expect(await isLimitRateHit(location.pathname, limitRate, storage)).toBeTruthy();
101101
});
102102
});

src/utils/isLimitRateHit/isLimitRateHit.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,33 @@ import type { LimitRate } from '../../types/LimitRate';
22
import type { StorageProvider } from '../../types/StorageProvider';
33
import { validateLimitRateParams } from '../validateLimitRateParams/validateLimitRateParams';
44

5-
const getLeftTime = (id: string, throttle: number, storage: StorageProvider): number => {
6-
const lastTime = Number(storage.get(id) || 0);
5+
const getLeftTime = async (
6+
id: string,
7+
throttle: number,
8+
storage: StorageProvider,
9+
): Promise<number> => {
10+
const lastTime = Number((await storage.get(id)) || 0);
711
return throttle - Date.now() + lastTime;
812
};
913

10-
const removeRecord = (id: string, leftTime: number, storage: StorageProvider): void => {
11-
setTimeout(() => {
12-
storage.remove(id);
13-
}, leftTime);
14-
};
15-
16-
export const isLimitRateHit = (
14+
export const isLimitRateHit = async (
1715
defaultID: string,
1816
options: LimitRate,
1917
storage?: StorageProvider,
20-
): boolean => {
18+
): Promise<boolean> => {
2119
if (!options.throttle || !storage) {
2220
return false;
2321
}
2422

2523
validateLimitRateParams(options.throttle, options.id);
2624

2725
const id = options.id || defaultID;
28-
const leftTime = getLeftTime(id, options.throttle, storage);
26+
const leftTime = await getLeftTime(id, options.throttle, storage);
2927

3028
if (leftTime > 0) {
31-
removeRecord(id, leftTime, storage);
3229
return true;
3330
}
3431

35-
storage.set(id, Date.now().toString());
36-
removeRecord(id, options.throttle, storage);
32+
await storage.set(id, Date.now().toString());
3733
return false;
3834
};

0 commit comments

Comments
 (0)