@tma.js/sdk 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dts/index.d.ts +1 -1
- package/dist/dts/init/creators/createViewport.d.ts +2 -9
- package/dist/dts/init/init.d.ts +2 -0
- package/dist/dts/init/types.d.ts +7 -4
- package/dist/dts/launch-params/index.d.ts +1 -0
- package/dist/dts/launch-params/retrieveFromUrl.d.ts +6 -0
- package/dist/dts/launch-params/types.d.ts +12 -8
- package/dist/dts/types/platform.d.ts +1 -1
- package/dist/dts/viewport/index.d.ts +1 -0
- package/dist/dts/viewport/isStableViewportPlatform.d.ts +7 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +469 -467
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/globals.ts +39 -0
- package/src/back-button/__tests__/BackButton.ts +129 -0
- package/src/bridge/__tests__/request.ts +236 -0
- package/src/bridge/env/__tests__/hasExternalNotify.ts +15 -0
- package/src/bridge/env/__tests__/hasWebviewProxy.ts +15 -0
- package/src/bridge/env/__tests__/isIframe.ts +30 -0
- package/src/bridge/events/__tests__/createEmitter.ts +143 -0
- package/src/bridge/events/__tests__/off.ts +34 -0
- package/src/bridge/events/__tests__/on.ts +49 -0
- package/src/bridge/events/__tests__/onTelegramEvent.ts +51 -0
- package/src/bridge/events/__tests__/once.ts +64 -0
- package/src/bridge/events/__tests__/singletonEmitter.ts +22 -0
- package/src/bridge/events/__tests__/subscribe.ts +49 -0
- package/src/bridge/events/__tests__/unsubscribe.ts +34 -0
- package/src/bridge/events/parsers/__tests__/clipboardTextReceived.ts +21 -0
- package/src/bridge/events/parsers/__tests__/invoiceClosed.ts +12 -0
- package/src/bridge/events/parsers/__tests__/popupClosed.ts +10 -0
- package/src/bridge/events/parsers/__tests__/qrTextReceived.ts +9 -0
- package/src/bridge/events/parsers/__tests__/theme-changed.ts +42 -0
- package/src/bridge/events/parsers/__tests__/viewportChanged.ts +49 -0
- package/src/bridge/methods/__tests__/createPostEvent.ts +37 -0
- package/src/bridge/methods/__tests__/postEvent.ts +137 -0
- package/src/classnames/__tests__/classNames.ts +20 -0
- package/src/classnames/__tests__/mergeClassNames.ts +21 -0
- package/src/closing-behavior/__tests__/ClosingBehavior.ts +86 -0
- package/src/colors/__tests__/isColorDark.ts +12 -0
- package/src/colors/__tests__/isRGB.ts +13 -0
- package/src/colors/__tests__/isRGBShort.ts +13 -0
- package/src/colors/__tests__/toRGB.ts +23 -0
- package/src/event-emitter/__tests__/EventEmitter.ts +145 -0
- package/src/haptic-feedback/__tests__/HapticFeedback.ts +68 -0
- package/src/index.ts +1 -0
- package/src/init/creators/__tests__/createViewport.ts +96 -0
- package/src/init/creators/createViewport.ts +60 -81
- package/src/init/init.ts +13 -15
- package/src/init/types.ts +8 -4
- package/src/init-data/__tests__/InitData.ts +98 -0
- package/src/init-data/__tests__/chatParser.ts +102 -0
- package/src/init-data/__tests__/initDataParser.ts +136 -0
- package/src/init-data/__tests__/parseInitData.ts +136 -0
- package/src/init-data/__tests__/userParser.ts +96 -0
- package/src/launch-params/__tests__/retrieveFromUrl.ts +19 -0
- package/src/launch-params/index.ts +1 -0
- package/src/launch-params/launchParamsParser.ts +4 -0
- package/src/launch-params/retrieveFromLocation.ts +2 -2
- package/src/launch-params/retrieveFromPerformance.ts +2 -7
- package/src/launch-params/retrieveFromUrl.ts +19 -0
- package/src/launch-params/types.ts +13 -8
- package/src/logger/__tests__/Logger.ts +107 -0
- package/src/main-button/__tests__/MainButton.ts +346 -0
- package/src/mini-app/__tests__/MiniApp.ts +140 -0
- package/src/misc/__tests__/isRecord.ts +21 -0
- package/src/navigation/HashNavigator/__tests__/HashNavigator.ts +144 -0
- package/src/navigation/HashNavigator/__tests__/drop.ts +42 -0
- package/src/navigation/HashNavigator/__tests__/go.ts +9 -0
- package/src/parsing/__tests__/ArrayValueParser.ts +18 -0
- package/src/parsing/__tests__/toRecord.ts +10 -0
- package/src/parsing/parsers/__tests__/array.ts +39 -0
- package/src/parsing/parsers/__tests__/boolean.ts +31 -0
- package/src/parsing/parsers/__tests__/date.ts +25 -0
- package/src/parsing/parsers/__tests__/json.ts +80 -0
- package/src/parsing/parsers/__tests__/number.ts +23 -0
- package/src/parsing/parsers/__tests__/rgb.ts +22 -0
- package/src/parsing/parsers/__tests__/searchParams.ts +105 -0
- package/src/parsing/parsers/__tests__/string.ts +25 -0
- package/src/popup/__tests__/Popup.ts +130 -0
- package/src/popup/__tests__/preparePopupParams.ts +85 -0
- package/src/supports/__tests__/supports.ts +123 -0
- package/src/theme-params/__tests__/keys.ts +19 -0
- package/src/theme-params/__tests__/parseThemeParams.ts +29 -0
- package/src/theme-params/__tests__/serializeThemeParams.ts +29 -0
- package/src/theme-params/__tests__/themeParamsParser.ts +29 -0
- package/src/timeout/__tests__/isTimeoutError.ts +9 -0
- package/src/timeout/__tests__/withTimeout.ts +28 -0
- package/src/types/platform.ts +2 -2
- package/src/version/__tests__/compareVersions.ts +19 -0
- package/src/viewport/__tests__/isStableViewportPlatform.ts +15 -0
- package/src/viewport/__tests__/utils.ts +12 -0
- package/src/viewport/index.ts +1 -0
- package/src/viewport/isStableViewportPlatform.ts +10 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// import {emitDesktopEvent, mockDesktop} from '../../../tests';
|
|
4
|
+
// import { Popup } from './Popup';
|
|
5
|
+
// import {Bridge} from '@tma.js/bridge';
|
|
6
|
+
// import {PopupParams} from './types';
|
|
7
|
+
// import {preparePopupParams} from './utils';
|
|
8
|
+
|
|
9
|
+
// beforeAll(mockDesktop);
|
|
10
|
+
|
|
11
|
+
describe('components', () => {
|
|
12
|
+
describe('Popup', () => {
|
|
13
|
+
it('should be fine', () => {
|
|
14
|
+
expect(true).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
// it('isOpened', () => {
|
|
17
|
+
// it('should emit event "openChange" with specified value in setter', () => {
|
|
18
|
+
// const popup = new Popup('7');
|
|
19
|
+
// const spy = vi.spyOn((popup as any).ee, 'emit');
|
|
20
|
+
// (popup as any).isOpened = true;
|
|
21
|
+
// expect(spy).lastCalledWith('openChange', true);
|
|
22
|
+
//
|
|
23
|
+
// (popup as any).isOpened = false;
|
|
24
|
+
// expect(spy).lastCalledWith('openChange', false);
|
|
25
|
+
// });
|
|
26
|
+
// });
|
|
27
|
+
//
|
|
28
|
+
// it('show', () => {
|
|
29
|
+
// it('should throw an error in case, current version is less than 6.2', () => {
|
|
30
|
+
// expect(() => new Popup('6.1').show({message: 'Hey!'})).toThrow();
|
|
31
|
+
// expect(() => new Popup('6.2').show({message: 'Hey!'})).not.toThrow();
|
|
32
|
+
// });
|
|
33
|
+
//
|
|
34
|
+
// it('should call bridge event "web_app_open_popup" with prepared parameters', () => {
|
|
35
|
+
// const bridge = new Bridge();
|
|
36
|
+
// const spy = vi.spyOn(bridge, 'postEvent');
|
|
37
|
+
// const popup = new Popup('7', {bridge});
|
|
38
|
+
// const params: PopupParams = {message: 'Message'};
|
|
39
|
+
// const prepared = preparePopupParams(params);
|
|
40
|
+
// popup.show(params);
|
|
41
|
+
// expect(spy).toHaveBeenCalledWith('web_app_open_popup', prepared);
|
|
42
|
+
// });
|
|
43
|
+
//
|
|
44
|
+
// it('should emit event "open" with prepared params', () => {
|
|
45
|
+
// const popup = new Popup('7');
|
|
46
|
+
// const spy = vi.spyOn((popup as any).ee, 'emit');
|
|
47
|
+
// const params: PopupParams = {message: 'Message'};
|
|
48
|
+
// const prepared = preparePopupParams(params);
|
|
49
|
+
// popup.show(params);
|
|
50
|
+
// expect(spy).toHaveBeenCalledWith('open', prepared);
|
|
51
|
+
// });
|
|
52
|
+
//
|
|
53
|
+
// it('should set "isOpened" property to true', () => {
|
|
54
|
+
// const popup = new Popup('7');
|
|
55
|
+
// expect(popup.isOpened).toBe(false);
|
|
56
|
+
// popup.show({message: 'Message'});
|
|
57
|
+
// expect(popup.isOpened).toBe(true);
|
|
58
|
+
// });
|
|
59
|
+
//
|
|
60
|
+
// it('should set "isOpened" property to false when promise is resolved', async () => {
|
|
61
|
+
// const popup = new Popup('7');
|
|
62
|
+
// const promise = popup.show({message: 'Message'});
|
|
63
|
+
//
|
|
64
|
+
// emitDesktopEvent('popup_closed', {button_id: null});
|
|
65
|
+
// await promise;
|
|
66
|
+
// expect(popup.isOpened).toBe(false);
|
|
67
|
+
// });
|
|
68
|
+
//
|
|
69
|
+
// it('should set "isOpened" property to true', () => {
|
|
70
|
+
// const popup = new Popup('7');
|
|
71
|
+
// popup.show({message: 'Message'});
|
|
72
|
+
// expect(popup.isOpened).toBe(true);
|
|
73
|
+
// });
|
|
74
|
+
//
|
|
75
|
+
// it('should emit close event with specified button_id when promise is resolved',
|
|
76
|
+
// async () => {
|
|
77
|
+
// const popup = new Popup('7');
|
|
78
|
+
// const spy = vi.spyOn((popup as any).ee, 'emit');
|
|
79
|
+
// const promise = popup.show({message: 'Message'});
|
|
80
|
+
// emitDesktopEvent('popup_closed', {button_id: 'Hey!'});
|
|
81
|
+
// await promise;
|
|
82
|
+
// expect(spy).lastCalledWith('close', 'Hey!');
|
|
83
|
+
// });
|
|
84
|
+
// });
|
|
85
|
+
//
|
|
86
|
+
// it('showAlert', () => {
|
|
87
|
+
// it('should call "show" with passed message and buttons = [{type: "close"}]', () => {
|
|
88
|
+
// const popup = new Popup('7');
|
|
89
|
+
// const spy = vi.spyOn(popup, 'show');
|
|
90
|
+
//
|
|
91
|
+
// popup.showAlert('Message');
|
|
92
|
+
//
|
|
93
|
+
// expect(spy).toHaveBeenCalledWith({
|
|
94
|
+
// message: 'Message',
|
|
95
|
+
// buttons: [{type: 'close'}],
|
|
96
|
+
// });
|
|
97
|
+
// });
|
|
98
|
+
// });
|
|
99
|
+
//
|
|
100
|
+
// it('showConfirm', () => {
|
|
101
|
+
// test(
|
|
102
|
+
// 'should call "show" with passed message and ' +
|
|
103
|
+
// 'buttons = [{type: "ok", id: "ok"}, {id: "cancel", type: "cancel"}]',
|
|
104
|
+
// () => {
|
|
105
|
+
// const popup = new Popup('7');
|
|
106
|
+
// const spy = vi.spyOn(popup, 'show');
|
|
107
|
+
//
|
|
108
|
+
// popup.showConfirm('Message');
|
|
109
|
+
//
|
|
110
|
+
// expect(spy).toHaveBeenCalledWith({
|
|
111
|
+
// message: 'Message',
|
|
112
|
+
// buttons: [{type: 'ok', id: 'ok'}, {id: 'cancel', type: 'cancel'}],
|
|
113
|
+
// });
|
|
114
|
+
// },
|
|
115
|
+
// );
|
|
116
|
+
//
|
|
117
|
+
// it('should resolve true in case, user pressed button with id "ok"', async () => {
|
|
118
|
+
// const promise = new Popup('7').showConfirm('Message');
|
|
119
|
+
// emitDesktopEvent('popup_closed', {button_id: 'ok'});
|
|
120
|
+
// expect(await promise).toBe(true);
|
|
121
|
+
// });
|
|
122
|
+
//
|
|
123
|
+
// it('should resolve false in case, user pressed any other button', async () => {
|
|
124
|
+
// const promise = new Popup('7').showConfirm('Message');
|
|
125
|
+
// emitDesktopEvent('popup_closed', {button_id: 'cancel'});
|
|
126
|
+
// await expect(promise).resolves.toBe(false);
|
|
127
|
+
// });
|
|
128
|
+
// });
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { preparePopupParams } from '../preparePopupParams';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates test text.
|
|
7
|
+
* @param length - text length.
|
|
8
|
+
*/
|
|
9
|
+
function createText(length: number): string {
|
|
10
|
+
return new Array(length).fill('a').join('');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
it('should throw an error in case, title length is more than 64 symbols', () => {
|
|
14
|
+
expect(() => preparePopupParams({
|
|
15
|
+
title: createText(65),
|
|
16
|
+
message: 'Hey!',
|
|
17
|
+
})).toThrow(/^Title has incorrect size/);
|
|
18
|
+
|
|
19
|
+
expect(() => preparePopupParams({
|
|
20
|
+
title: createText(64),
|
|
21
|
+
message: 'Hey!',
|
|
22
|
+
})).not.toThrow();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should throw an error in case, message length is zero or more than 256 symbols', () => {
|
|
26
|
+
expect(() => preparePopupParams({
|
|
27
|
+
message: '',
|
|
28
|
+
})).toThrow(/^Message has incorrect size/);
|
|
29
|
+
|
|
30
|
+
expect(() => preparePopupParams({
|
|
31
|
+
message: createText(257),
|
|
32
|
+
})).toThrow(/^Message has incorrect size/);
|
|
33
|
+
|
|
34
|
+
expect(() => preparePopupParams({
|
|
35
|
+
message: createText(256),
|
|
36
|
+
})).not.toThrow();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should throw an error in case, buttons count is more than 3', () => {
|
|
40
|
+
expect(() => preparePopupParams({
|
|
41
|
+
message: 'a',
|
|
42
|
+
buttons: new Array(4).fill({ type: 'close' }),
|
|
43
|
+
})).toThrow(/^Buttons have incorrect size/);
|
|
44
|
+
|
|
45
|
+
expect(() => preparePopupParams({
|
|
46
|
+
message: 'a',
|
|
47
|
+
buttons: new Array(3).fill({ type: 'close' }),
|
|
48
|
+
})).not.toThrow();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should append button type "close" in case, buttons array is empty', () => {
|
|
52
|
+
expect(preparePopupParams({ message: 'a' }).buttons).toStrictEqual([{
|
|
53
|
+
type: 'close',
|
|
54
|
+
id: '',
|
|
55
|
+
}]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw an error in case, some button text length size is zero or more than 64 symbols', () => {
|
|
59
|
+
expect(() => preparePopupParams({
|
|
60
|
+
message: 'A',
|
|
61
|
+
buttons: [{ type: 'default', text: createText(65) }],
|
|
62
|
+
})).toThrowError(/^Button text with type/);
|
|
63
|
+
|
|
64
|
+
expect(() => preparePopupParams({
|
|
65
|
+
message: 'A',
|
|
66
|
+
buttons: [{ type: 'default', text: '' }],
|
|
67
|
+
})).toThrowError(/^Button text with type/);
|
|
68
|
+
|
|
69
|
+
expect(() => preparePopupParams({
|
|
70
|
+
message: 'A',
|
|
71
|
+
buttons: [{ type: 'default', text: createText(64) }],
|
|
72
|
+
})).not.toThrow();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should fulfill all optional popup parameters', () => {
|
|
76
|
+
expect(preparePopupParams({
|
|
77
|
+
message: 'Message',
|
|
78
|
+
buttons: [{ type: 'default', text: 'Wow!' }, { type: 'close' }],
|
|
79
|
+
}))
|
|
80
|
+
.toStrictEqual({
|
|
81
|
+
title: '',
|
|
82
|
+
message: 'Message',
|
|
83
|
+
buttons: [{ id: '', type: 'default', text: 'Wow!' }, { type: 'close', id: '' }],
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
MiniAppsMethodName,
|
|
5
|
+
MiniAppsMethodVersionedParams,
|
|
6
|
+
MiniAppsMethodWithVersionedParams,
|
|
7
|
+
} from '../../bridge';
|
|
8
|
+
import type { Version } from '../../version';
|
|
9
|
+
import { supports } from '../supports';
|
|
10
|
+
|
|
11
|
+
type HaveCheckSupportMethodTuple = {
|
|
12
|
+
[M in MiniAppsMethodWithVersionedParams]: [M, MiniAppsMethodVersionedParams<M>]
|
|
13
|
+
}[MiniAppsMethodWithVersionedParams];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Increases specified version by amount of updates.
|
|
17
|
+
* @param version - initial version.
|
|
18
|
+
* @param amount - count of bumps.
|
|
19
|
+
*/
|
|
20
|
+
function increaseVersion(version: Version, amount: number): string {
|
|
21
|
+
const match = version.match(/(.+\.)(\d+)$/);
|
|
22
|
+
if (!match) {
|
|
23
|
+
throw new Error(`Invalid version: ${version}`);
|
|
24
|
+
}
|
|
25
|
+
return `${match[1]}${parseInt(match[2], 10) + amount}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tests: [
|
|
29
|
+
version: Version | 'any',
|
|
30
|
+
methods: (MiniAppsMethodName | HaveCheckSupportMethodTuple)[],
|
|
31
|
+
][] = [
|
|
32
|
+
['any', [
|
|
33
|
+
'iframe_ready',
|
|
34
|
+
'iframe_will_reload',
|
|
35
|
+
'web_app_close',
|
|
36
|
+
'web_app_data_send',
|
|
37
|
+
'web_app_expand',
|
|
38
|
+
'web_app_open_link',
|
|
39
|
+
'web_app_ready',
|
|
40
|
+
'web_app_request_theme',
|
|
41
|
+
'web_app_request_viewport',
|
|
42
|
+
'web_app_setup_main_button',
|
|
43
|
+
'web_app_setup_closing_behavior',
|
|
44
|
+
]],
|
|
45
|
+
['6.1', [
|
|
46
|
+
'web_app_open_tg_link',
|
|
47
|
+
'web_app_open_invoice',
|
|
48
|
+
'web_app_setup_back_button',
|
|
49
|
+
'web_app_set_background_color',
|
|
50
|
+
'web_app_set_header_color',
|
|
51
|
+
'web_app_trigger_haptic_feedback',
|
|
52
|
+
]],
|
|
53
|
+
['6.2', [
|
|
54
|
+
'web_app_open_popup',
|
|
55
|
+
]],
|
|
56
|
+
['6.4', [
|
|
57
|
+
'web_app_read_text_from_clipboard',
|
|
58
|
+
'web_app_close_scan_qr_popup',
|
|
59
|
+
'web_app_close_scan_qr_popup',
|
|
60
|
+
['web_app_open_link', 'try_instant_view'],
|
|
61
|
+
]],
|
|
62
|
+
['6.7', [
|
|
63
|
+
'web_app_switch_inline_query',
|
|
64
|
+
]],
|
|
65
|
+
['6.9', [
|
|
66
|
+
'web_app_invoke_custom_method',
|
|
67
|
+
'web_app_request_write_access',
|
|
68
|
+
'web_app_request_phone',
|
|
69
|
+
['web_app_set_header_color', 'color'],
|
|
70
|
+
]],
|
|
71
|
+
['6.10', [
|
|
72
|
+
'web_app_setup_settings_button',
|
|
73
|
+
]],
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
tests.forEach(([version, methods]) => {
|
|
77
|
+
if (version === 'any') {
|
|
78
|
+
methods.forEach((methodOrTuple) => {
|
|
79
|
+
if (Array.isArray(methodOrTuple)) {
|
|
80
|
+
const [method, param] = methodOrTuple;
|
|
81
|
+
it(`should return true in case, passed method is "${method}", parameter is "${param}" and version is 1`, () => {
|
|
82
|
+
expect(supports(method, param, '1')).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const method = methodOrTuple;
|
|
89
|
+
it(`should return true in case, passed method is "${method}" and version is 1`, () => {
|
|
90
|
+
expect(supports(method, '1')).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
methods.forEach((methodOrTuple) => {
|
|
97
|
+
if (Array.isArray(methodOrTuple)) {
|
|
98
|
+
const [method, param] = methodOrTuple;
|
|
99
|
+
|
|
100
|
+
it(`should return true in case, passed method is "${method}", parameter is "${param}" and version is ${version} or higher`, () => {
|
|
101
|
+
expect(supports(method, param, version)).toBe(true);
|
|
102
|
+
expect(supports(method, param, increaseVersion(version, 1))).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it(`should return false in case, passed method is "${method}", parameter is "${param}" and version is lower than ${version}`, () => {
|
|
106
|
+
expect(supports(method, param, increaseVersion(version, -1))).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const method = methodOrTuple;
|
|
113
|
+
|
|
114
|
+
it(`should return true in case, passed method is "${method}" and version is ${version} or higher`, () => {
|
|
115
|
+
expect(supports(method, version)).toBe(true);
|
|
116
|
+
expect(supports(method, increaseVersion(version, 1))).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it(`should return false in case, passed method is "${method}" and version is lower than ${version}`, () => {
|
|
120
|
+
expect(supports(method, increaseVersion(version, -1))).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { keyToExternal, keyToLocal } from '../keys';
|
|
4
|
+
|
|
5
|
+
describe('keyToLocal', () => {
|
|
6
|
+
it('should replace "^bg" and "_bg" with "background" and "_background". Then replace _[a-z] with [A-Z]', () => {
|
|
7
|
+
expect(keyToLocal('bg_color')).toBe('backgroundColor');
|
|
8
|
+
expect(keyToLocal('secondary_bg_color')).toBe('secondaryBackgroundColor');
|
|
9
|
+
expect(keyToLocal('text_color')).toBe('textColor');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('keyToExternal', () => {
|
|
14
|
+
it('should replace [A-Z] with _[a-z]. Then replace "background" and "_background" with "^bg" and "_bg"', () => {
|
|
15
|
+
expect(keyToExternal('backgroundColor')).toBe('bg_color');
|
|
16
|
+
expect(keyToExternal('secondaryBackgroundColor')).toBe('secondary_bg_color');
|
|
17
|
+
expect(keyToExternal('textColor')).toBe('text_color');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseThemeParams } from '../parseThemeParams';
|
|
4
|
+
|
|
5
|
+
[
|
|
6
|
+
['accent_text_color', 'accentTextColor'],
|
|
7
|
+
['bg_color', 'backgroundColor'],
|
|
8
|
+
['button_color', 'buttonColor'],
|
|
9
|
+
['button_text_color', 'buttonTextColor'],
|
|
10
|
+
['destructive_text_color', 'destructiveTextColor'],
|
|
11
|
+
['header_bg_color', 'headerBackgroundColor'],
|
|
12
|
+
['hint_color', 'hintColor'],
|
|
13
|
+
['link_color', 'linkColor'],
|
|
14
|
+
['secondary_bg_color', 'secondaryBackgroundColor'],
|
|
15
|
+
['section_header_text_color', 'sectionHeaderTextColor'],
|
|
16
|
+
['section_bg_color', 'sectionBackgroundColor'],
|
|
17
|
+
['subtitle_text_color', 'subtitleTextColor'],
|
|
18
|
+
['text_color', 'textColor'],
|
|
19
|
+
].forEach(([from, to]) => {
|
|
20
|
+
describe(to, () => {
|
|
21
|
+
it(`should throw if "${from}" property contains not a string in format "#RRGGBB"`, () => {
|
|
22
|
+
expect(() => parseThemeParams({ [from]: 999 })).toThrow();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it(`should map to "${to}" property parsing it as string in "#RRGGBB" format`, () => {
|
|
26
|
+
expect(parseThemeParams({ [from]: '#aabbcc' })).toStrictEqual({ [to]: '#aabbcc' });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { serializeThemeParams } from '../serializeThemeParams';
|
|
4
|
+
|
|
5
|
+
[
|
|
6
|
+
['accent_text_color', 'accentTextColor'],
|
|
7
|
+
['bg_color', 'backgroundColor'],
|
|
8
|
+
['button_color', 'buttonColor'],
|
|
9
|
+
['button_text_color', 'buttonTextColor'],
|
|
10
|
+
['destructive_text_color', 'destructiveTextColor'],
|
|
11
|
+
['header_bg_color', 'headerBackgroundColor'],
|
|
12
|
+
['hint_color', 'hintColor'],
|
|
13
|
+
['link_color', 'linkColor'],
|
|
14
|
+
['secondary_bg_color', 'secondaryBackgroundColor'],
|
|
15
|
+
['section_header_text_color', 'sectionHeaderTextColor'],
|
|
16
|
+
['section_bg_color', 'sectionBackgroundColor'],
|
|
17
|
+
['subtitle_text_color', 'subtitleTextColor'],
|
|
18
|
+
['text_color', 'textColor'],
|
|
19
|
+
].forEach(([to, from]) => {
|
|
20
|
+
describe(from, () => {
|
|
21
|
+
it(`should omit the "${to}" property in case this property is missing`, () => {
|
|
22
|
+
expect(serializeThemeParams({})).not.toMatch(`"${to}"`);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it(`should map this property to "${to}" property`, () => {
|
|
26
|
+
expect(serializeThemeParams({ [from]: '#aabbcc' })).toBe(`{"${to}":"#aabbcc"}`);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { themeParamsParser } from '../themeParamsParser';
|
|
4
|
+
|
|
5
|
+
[
|
|
6
|
+
['accent_text_color', 'accentTextColor'],
|
|
7
|
+
['bg_color', 'backgroundColor'],
|
|
8
|
+
['button_color', 'buttonColor'],
|
|
9
|
+
['button_text_color', 'buttonTextColor'],
|
|
10
|
+
['destructive_text_color', 'destructiveTextColor'],
|
|
11
|
+
['header_bg_color', 'headerBackgroundColor'],
|
|
12
|
+
['hint_color', 'hintColor'],
|
|
13
|
+
['link_color', 'linkColor'],
|
|
14
|
+
['secondary_bg_color', 'secondaryBackgroundColor'],
|
|
15
|
+
['section_header_text_color', 'sectionHeaderTextColor'],
|
|
16
|
+
['section_bg_color', 'sectionBackgroundColor'],
|
|
17
|
+
['subtitle_text_color', 'subtitleTextColor'],
|
|
18
|
+
['text_color', 'textColor'],
|
|
19
|
+
].forEach(([from, to]) => {
|
|
20
|
+
describe(to, () => {
|
|
21
|
+
it(`should throw if "${from}" property contains not a string in format "#RRGGBB"`, () => {
|
|
22
|
+
expect(() => themeParamsParser().parse({ [from]: 999 })).toThrow();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it(`should map to "${to}" property parsing it as string in "#RRGGBB" format`, () => {
|
|
26
|
+
expect(themeParamsParser().parse({ [from]: '#aabbcc' })).toStrictEqual({ [to]: '#aabbcc' });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { isTimeoutError } from '../isTimeoutError';
|
|
4
|
+
import { TimeoutError } from '../TimeoutError';
|
|
5
|
+
|
|
6
|
+
it('should return true if passed value is instance of TimeoutError', () => {
|
|
7
|
+
expect(isTimeoutError(null)).toBe(false);
|
|
8
|
+
expect(isTimeoutError(new TimeoutError(1000))).toBe(true);
|
|
9
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { afterAll, beforeAll, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { TimeoutError, withTimeout } from '../index';
|
|
4
|
+
|
|
5
|
+
beforeAll(() => {
|
|
6
|
+
vi.useFakeTimers();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
afterAll(() => {
|
|
10
|
+
vi.useRealTimers();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should throw an error in case timeout reached', () => {
|
|
14
|
+
const promise = withTimeout(() => new Promise((res) => {
|
|
15
|
+
setTimeout(res, 500);
|
|
16
|
+
}), 100);
|
|
17
|
+
|
|
18
|
+
Promise.resolve().then(() => vi.advanceTimersByTime(500));
|
|
19
|
+
expect(promise).rejects.toStrictEqual(new TimeoutError(100));
|
|
20
|
+
}, 1000);
|
|
21
|
+
|
|
22
|
+
it('should return resolved value by wrapped function', () => {
|
|
23
|
+
const promise = withTimeout(() => new Promise((res) => {
|
|
24
|
+
res('I am fine');
|
|
25
|
+
}), 100);
|
|
26
|
+
|
|
27
|
+
expect(promise).resolves.toBe('I am fine');
|
|
28
|
+
}, 1000);
|
package/src/types/platform.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { compareVersions } from '../compareVersions';
|
|
4
|
+
|
|
5
|
+
it('should return 1 in case "a" is greater than "b"', () => {
|
|
6
|
+
expect(compareVersions('6.1', '6.0')).toBe(1);
|
|
7
|
+
expect(compareVersions('6.1', '6')).toBe(1);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should return 0 in case "a" is equal to "b"', () => {
|
|
11
|
+
expect(compareVersions('6', '6')).toBe(0);
|
|
12
|
+
expect(compareVersions('6', '6.0')).toBe(0);
|
|
13
|
+
expect(compareVersions('6.0', '6')).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return -1 in case "a" is lower than "b"', () => {
|
|
17
|
+
expect(compareVersions('5', '6.0')).toBe(-1);
|
|
18
|
+
expect(compareVersions('6.0', '6.1')).toBe(-1);
|
|
19
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { isStableViewportPlatform } from '../isStableViewportPlatform';
|
|
4
|
+
|
|
5
|
+
['macos', 'tdesktop', 'unigram', 'web', 'weba'].forEach((platform) => {
|
|
6
|
+
it(`should return true if passed platform is "${platform}"`, () => {
|
|
7
|
+
expect(isStableViewportPlatform(platform)).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
['unknown', 'android', 'android_x'].forEach((platform) => {
|
|
12
|
+
it(`should return false if passed platform is "${platform}"`, () => {
|
|
13
|
+
expect(isStableViewportPlatform(platform)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { truncate } from '../utils';
|
|
4
|
+
|
|
5
|
+
it('should return zero if value is less than 0', () => {
|
|
6
|
+
expect(truncate(-1)).toBe(0);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should return value if it is equals to or higher than 0', () => {
|
|
10
|
+
expect(truncate(0)).toBe(0);
|
|
11
|
+
expect(truncate(20)).toBe(20);
|
|
12
|
+
});
|
package/src/viewport/index.ts
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Platform } from '~/types/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns true if specified platform has stable viewport. Stable means not changing from time to
|
|
5
|
+
* time.
|
|
6
|
+
* @param platform - platform identifier.
|
|
7
|
+
*/
|
|
8
|
+
export function isStableViewportPlatform(platform: Platform): boolean {
|
|
9
|
+
return ['macos', 'tdesktop', 'unigram', 'web', 'weba'].includes(platform);
|
|
10
|
+
}
|