@tencentcloud/web-push 1.0.3 → 1.0.5

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +100 -92
  3. package/{dist/index.esm.js → index.esm.js} +1 -1
  4. package/{dist/index.umd.js → index.umd.js} +1 -1
  5. package/package.json +9 -47
  6. package/sw.js +1 -0
  7. package/dist/sw.js +0 -1
  8. package/src/__tests__/index.test.ts +0 -120
  9. package/src/__tests__/integration.test.ts +0 -285
  10. package/src/__tests__/setup.ts +0 -210
  11. package/src/__tests__/types.test.ts +0 -303
  12. package/src/__tests__/web-push-sdk.test.ts +0 -257
  13. package/src/components/message-popup.ts +0 -1007
  14. package/src/core/event-emitter.ts +0 -61
  15. package/src/core/service-worker-manager.ts +0 -614
  16. package/src/core/web-push-sdk.ts +0 -690
  17. package/src/debug/GenerateTestUserSig.js +0 -37
  18. package/src/debug/index.d.ts +0 -6
  19. package/src/debug/index.js +0 -1
  20. package/src/debug/lib-generate-test-usersig-es.min.js +0 -2
  21. package/src/index.ts +0 -9
  22. package/src/service-worker/sw.ts +0 -494
  23. package/src/types/index.ts +0 -2
  24. package/src/types/inner.ts +0 -44
  25. package/src/types/outer.ts +0 -142
  26. package/src/utils/browser-support.ts +0 -412
  27. package/src/utils/logger.ts +0 -66
  28. package/src/utils/storage.ts +0 -51
  29. package/src/utils/validator.ts +0 -267
  30. /package/{dist/index.d.ts → index.d.ts} +0 -0
  31. /package/{dist/src → src}/components/message-popup.d.ts +0 -0
  32. /package/{dist/src → src}/core/event-emitter.d.ts +0 -0
  33. /package/{dist/src → src}/core/service-worker-manager.d.ts +0 -0
  34. /package/{dist/src → src}/core/web-push-sdk.d.ts +0 -0
  35. /package/{dist/src → src}/index.d.ts +0 -0
  36. /package/{dist/src → src}/service-worker/sw.d.ts +0 -0
  37. /package/{dist/src → src}/types/index.d.ts +0 -0
  38. /package/{dist/src → src}/types/inner.d.ts +0 -0
  39. /package/{dist/src → src}/types/outer.d.ts +0 -0
  40. /package/{dist/src → src}/utils/browser-support.d.ts +0 -0
  41. /package/{dist/src → src}/utils/logger.d.ts +0 -0
  42. /package/{dist/src → src}/utils/storage.d.ts +0 -0
  43. /package/{dist/src → src}/utils/validator.d.ts +0 -0
@@ -1,210 +0,0 @@
1
- /**
2
- * Jest test environment setup file
3
- * Executed before each test file runs
4
- */
5
-
6
- // Setup global test environment
7
- Object.defineProperty(window, 'matchMedia', {
8
- writable: true,
9
- value: jest.fn().mockImplementation((query) => ({
10
- matches: false,
11
- media: query,
12
- onchange: null,
13
- addListener: jest.fn(), // deprecated
14
- removeListener: jest.fn(), // deprecated
15
- addEventListener: jest.fn(),
16
- removeEventListener: jest.fn(),
17
- dispatchEvent: jest.fn(),
18
- })),
19
- });
20
-
21
- // Mock Service Worker API
22
- Object.defineProperty(window, 'navigator', {
23
- writable: true,
24
- value: {
25
- ...window.navigator,
26
- userAgent:
27
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
28
- platform: 'MacIntel',
29
- language: 'en-US',
30
- languages: ['en-US', 'en'],
31
- serviceWorker: {
32
- register: jest.fn().mockResolvedValue({
33
- installing: null,
34
- waiting: null,
35
- active: null,
36
- addEventListener: jest.fn(),
37
- removeEventListener: jest.fn(),
38
- update: jest.fn(),
39
- unregister: jest.fn(),
40
- }),
41
- ready: Promise.resolve({
42
- installing: null,
43
- waiting: null,
44
- active: null,
45
- addEventListener: jest.fn(),
46
- removeEventListener: jest.fn(),
47
- update: jest.fn(),
48
- unregister: jest.fn(),
49
- }),
50
- controller: null,
51
- addEventListener: jest.fn(),
52
- removeEventListener: jest.fn(),
53
- },
54
- },
55
- });
56
-
57
- // Mock ServiceWorkerManager globally
58
- jest.mock('../core/service-worker-manager', () => {
59
- const mockServiceWorkerManager = {
60
- register: jest.fn().mockResolvedValue(undefined),
61
- getPushSubscription: jest.fn().mockResolvedValue({
62
- subscription: {
63
- endpoint: 'https://example.com/push',
64
- keys: { auth: 'mock-auth', p256dh: 'mock-p256dh' },
65
- },
66
- token: 'mock-token',
67
- auth: 'mock-auth',
68
- p256dh: 'mock-p256dh',
69
- }),
70
- unsubscribe: jest.fn().mockResolvedValue(true),
71
- unregister: jest.fn().mockResolvedValue(true),
72
- };
73
-
74
- return {
75
- ServiceWorkerManager: {
76
- getInstance: jest.fn().mockReturnValue(mockServiceWorkerManager),
77
- },
78
- };
79
- });
80
-
81
- // Mock browser support
82
- jest.mock('../utils/browser-support', () => ({
83
- browserSupport: {
84
- detectWebPushCapability: jest.fn().mockReturnValue({
85
- supported: true,
86
- browserName: 'Chrome',
87
- browserVersion: '120.0.0',
88
- }),
89
- isWebPushSupported: jest.fn().mockReturnValue(true),
90
- getUnsupportedReason: jest.fn().mockReturnValue(undefined),
91
- checkNotificationPermission: jest.fn().mockResolvedValue('granted'),
92
- requestNotificationPermission: jest.fn().mockResolvedValue('granted'),
93
- requiresUserGesture: jest.fn().mockReturnValue(false),
94
- handleBrowserSpecificError: jest
95
- .fn()
96
- .mockImplementation((error: Error) => error),
97
- checkBrowserSupport: jest.fn().mockReturnValue(true),
98
- getBrowserInfo: jest.fn().mockReturnValue({
99
- name: 'Chrome',
100
- version: '120.0.0',
101
- majorVersion: 120,
102
- platform: 'macOS',
103
- userAgent: 'Chrome/120.0.0',
104
- }),
105
- getFeatureSupport: jest.fn().mockReturnValue({
106
- serviceWorker: true,
107
- pushManager: true,
108
- notification: true,
109
- webPush: true,
110
- }),
111
- },
112
- // 导出便捷函数
113
- getBrowserInfo: jest.fn().mockReturnValue({
114
- name: 'Chrome',
115
- version: '120.0.0',
116
- majorVersion: 120,
117
- platform: 'macOS',
118
- userAgent: 'Chrome/120.0.0',
119
- }),
120
- getFeatureSupport: jest.fn().mockReturnValue({
121
- serviceWorker: true,
122
- pushManager: true,
123
- notification: true,
124
- webPush: true,
125
- }),
126
- detectWebPushCapability: jest.fn().mockReturnValue({
127
- supported: true,
128
- browserName: 'Chrome',
129
- browserVersion: '120.0.0',
130
- }),
131
- isWebPushSupported: jest.fn().mockReturnValue(true),
132
- getUnsupportedReason: jest.fn().mockReturnValue(undefined),
133
- }));
134
-
135
- jest.mock('../utils/storage', () => ({
136
- Storage: {
137
- set: jest.fn(),
138
- get: jest.fn().mockReturnValue(null),
139
- remove: jest.fn(),
140
- },
141
- }));
142
-
143
- jest.mock('../utils/logger', () => ({
144
- logger: {
145
- log: jest.fn(),
146
- warn: jest.fn(),
147
- error: jest.fn(),
148
- info: jest.fn(),
149
- },
150
- }));
151
-
152
- // Mock TencentCloud Chat SDK
153
- const mockChatInstance = {
154
- login: jest.fn().mockResolvedValue({ code: 0 }),
155
- logout: jest.fn().mockResolvedValue({ code: 0 }),
156
- on: jest.fn(),
157
- off: jest.fn(),
158
- destroy: jest.fn().mockResolvedValue({ code: 0 }),
159
- callExperimentalAPI: jest.fn().mockResolvedValue({ code: 0 }),
160
- };
161
-
162
- const mockChatSDK = {
163
- create: jest.fn().mockReturnValue(mockChatInstance),
164
- };
165
-
166
- jest.mock('@tencentcloud/lite-chat/basic', () => ({
167
- __esModule: true,
168
- default: mockChatSDK,
169
- }));
170
-
171
- // Mock genTestUserSig function
172
- jest.mock('../debug/lib-generate-test-usersig-es.min.js', () => ({
173
- __esModule: true,
174
- default: jest.fn().mockImplementation(() => ({
175
- genTestUserSig: jest.fn().mockReturnValue('mock-user-sig'),
176
- })),
177
- }));
178
-
179
- // Mock Notification API
180
- Object.defineProperty(window, 'Notification', {
181
- writable: true,
182
- value: class MockNotification {
183
- static permission = 'default';
184
- static requestPermission = jest.fn().mockResolvedValue('granted');
185
-
186
- constructor(_title: string, _options?: NotificationOptions) {
187
- // Mock notification instance
188
- }
189
-
190
- close = jest.fn();
191
- addEventListener = jest.fn();
192
- removeEventListener = jest.fn();
193
- },
194
- });
195
-
196
- // Mock PushManager API
197
- Object.defineProperty(window, 'PushManager', {
198
- writable: true,
199
- value: {
200
- supportedContentEncodings: ['aes128gcm'],
201
- },
202
- });
203
-
204
- // Set test timeout
205
- jest.setTimeout(10000);
206
-
207
- // Cleanup after each test
208
- afterEach(() => {
209
- jest.clearAllMocks();
210
- });
@@ -1,303 +0,0 @@
1
- /**
2
- * 类型定义测试
3
- */
4
- import {
5
- EVENT,
6
- RegisterPushOptions,
7
- NotificationMessage,
8
- NotificationClickData,
9
- StatisticsData,
10
- Message,
11
- MessageReceivedResult,
12
- MessageRevokedResult,
13
- MessageNotificationClickedResult,
14
- EventResult,
15
- WebPushSDK,
16
- ServiceWorkerMessage,
17
- SubscriptionInfo,
18
- } from '../types';
19
-
20
- describe('类型定义测试', () => {
21
- describe('EVENT 枚举测试', () => {
22
- it('应该包含所有必需的事件类型', () => {
23
- expect(EVENT.MESSAGE_RECEIVED).toBe('message_received');
24
- expect(EVENT.MESSAGE_REVOKED).toBe('message_revoked');
25
- expect(EVENT.NOTIFICATION_CLICKED).toBe('notification_clicked');
26
- });
27
-
28
- it('EVENT 应该是只读的', () => {
29
- // TypeScript 编译时会检查这个,运行时我们验证值的正确性
30
- expect(Object.keys(EVENT)).toHaveLength(3);
31
- expect(Object.values(EVENT)).toEqual([
32
- 'message_received',
33
- 'message_revoked',
34
- 'notification_clicked',
35
- ]);
36
- });
37
- });
38
-
39
- describe('Event 类型测试', () => {
40
- it('应该接受有效的事件类型', () => {
41
- const validEvents: EVENT[] = [
42
- EVENT.MESSAGE_RECEIVED,
43
- EVENT.MESSAGE_REVOKED,
44
- EVENT.NOTIFICATION_CLICKED,
45
- ];
46
-
47
- validEvents.forEach((event) => {
48
- expect(typeof event).toBe('string');
49
- expect(Object.values(EVENT)).toContain(event);
50
- });
51
- });
52
- });
53
-
54
- describe('RegisterPushOptions 接口测试', () => {
55
- it('应该包含必需的属性', () => {
56
- const options: RegisterPushOptions = {
57
- SDKAppID: 123456,
58
- appKey: 'test-app-key',
59
- userID: 'test-user-id',
60
- };
61
-
62
- expect(typeof options.SDKAppID).toBe('number');
63
- expect(typeof options.appKey).toBe('string');
64
- expect(typeof options.userID).toBe('string');
65
- });
66
-
67
- it('应该支持可选的 serviceWorkerPath', () => {
68
- const optionsWithSW: RegisterPushOptions = {
69
- SDKAppID: 123456,
70
- appKey: 'test-app-key',
71
- userID: 'test-user-id',
72
- serviceWorkerPath: '/custom-sw.js',
73
- };
74
-
75
- expect(typeof optionsWithSW.serviceWorkerPath).toBe('string');
76
- });
77
- });
78
-
79
- describe('NotificationMessage 接口测试', () => {
80
- it('应该包含必需的属性', () => {
81
- const message: NotificationMessage = {
82
- messageID: 'msg-123',
83
- title: 'Test Title',
84
- body: 'Test Body',
85
- timestamp: Date.now(),
86
- };
87
-
88
- expect(typeof message.messageID).toBe('string');
89
- expect(typeof message.title).toBe('string');
90
- expect(typeof message.body).toBe('string');
91
- expect(typeof message.timestamp).toBe('number');
92
- });
93
-
94
- it('应该支持可选属性', () => {
95
- const messageWithOptional: NotificationMessage = {
96
- messageID: 'msg-123',
97
- title: 'Test Title',
98
- body: 'Test Body',
99
- timestamp: Date.now(),
100
- icon: '/icon.png',
101
- tag: 'test-tag',
102
- data: { custom: 'data' },
103
- };
104
-
105
- expect(typeof messageWithOptional.icon).toBe('string');
106
- expect(typeof messageWithOptional.tag).toBe('string');
107
- expect(typeof messageWithOptional.data).toBe('object');
108
- });
109
- });
110
-
111
- describe('NotificationClickData 接口测试', () => {
112
- it('应该包含通知对象', () => {
113
- const message: NotificationMessage = {
114
- messageID: 'msg-123',
115
- title: 'Test Title',
116
- body: 'Test Body',
117
- timestamp: Date.now(),
118
- };
119
-
120
- const clickData: NotificationClickData = {
121
- notification: message,
122
- };
123
-
124
- expect(clickData.notification).toBe(message);
125
- });
126
-
127
- it('应该支持可选的 action', () => {
128
- const message: NotificationMessage = {
129
- messageID: 'msg-123',
130
- title: 'Test Title',
131
- body: 'Test Body',
132
- timestamp: Date.now(),
133
- };
134
-
135
- const clickDataWithAction: NotificationClickData = {
136
- notification: message,
137
- action: 'reply',
138
- };
139
-
140
- expect(typeof clickDataWithAction.action).toBe('string');
141
- });
142
- });
143
-
144
- describe('StatisticsData 接口测试', () => {
145
- it('应该包含统计数据的所有属性', () => {
146
- const statsData: StatisticsData = {
147
- messageID: 'msg-123',
148
- type: 'reach',
149
- timestamp: Date.now(),
150
- SDKAppID: 123456,
151
- registrationID: 'reg-123',
152
- };
153
-
154
- expect(typeof statsData.messageID).toBe('string');
155
- expect(['reach', 'click']).toContain(statsData.type);
156
- expect(typeof statsData.timestamp).toBe('number');
157
- expect(typeof statsData.SDKAppID).toBe('number');
158
- expect(typeof statsData.registrationID).toBe('string');
159
- });
160
- });
161
-
162
- describe('Message 接口测试', () => {
163
- it('应该包含消息的所有必需属性', () => {
164
- const message: Message = {
165
- ID: 'msg-123',
166
- type: 'TIMTextElem',
167
- payload: { text: 'Hello' },
168
- conversationID: 'conv-123',
169
- conversationType: 'C2C',
170
- to: 'user-456',
171
- from: 'user-123',
172
- flow: 'in',
173
- time: Date.now(),
174
- status: 'success',
175
- isRevoked: false,
176
- nick: 'Test User',
177
- avatar: '/avatar.jpg',
178
- isPeerRead: false,
179
- nameCard: 'Test Card',
180
- atUserList: [],
181
- cloudCustomData: '{}',
182
- isDeleted: false,
183
- isModified: false,
184
- needReadReceipt: false,
185
- readReceiptInfo: {},
186
- isBroadcastMessage: false,
187
- isSupportExtension: true,
188
- revoker: '',
189
- sequence: 1,
190
- progress: 100,
191
- revokerInfo: {
192
- userID: '',
193
- nick: '',
194
- avatar: '',
195
- },
196
- revokeReason: '',
197
- hasRiskContent: false,
198
- };
199
-
200
- expect(typeof message.ID).toBe('string');
201
- expect([
202
- 'TIMTextElem',
203
- 'TIMImageElem',
204
- 'TIMSoundElem',
205
- 'TIMVideoFileElem',
206
- 'TIMFileElem',
207
- 'TIMCustomElem',
208
- 'TIMRelayElem',
209
- 'TIMLocationElem',
210
- 'TIMFaceElem',
211
- ]).toContain(message.type);
212
- expect(['C2C', 'GROUP']).toContain(message.conversationType);
213
- });
214
- });
215
-
216
- describe('WebPushSDK 接口测试', () => {
217
- it('应该定义所有必需的方法', () => {
218
- // 这个测试主要是类型检查,确保接口定义正确
219
- const mockSDK: WebPushSDK = {
220
- registerPush: jest.fn(),
221
- unRegisterPush: jest.fn(),
222
- addPushListener: jest.fn(),
223
- removePushListener: jest.fn(),
224
- EVENT: EVENT,
225
- };
226
-
227
- expect(typeof mockSDK.registerPush).toBe('function');
228
- expect(typeof mockSDK.unRegisterPush).toBe('function');
229
- expect(typeof mockSDK.addPushListener).toBe('function');
230
- expect(typeof mockSDK.removePushListener).toBe('function');
231
- expect(mockSDK.EVENT).toBe(EVENT);
232
- });
233
- });
234
-
235
- describe('ServiceWorkerMessage 接口测试', () => {
236
- it('应该支持所有消息类型', () => {
237
- const messages: ServiceWorkerMessage[] = [
238
- { type: 'MESSAGE_RECEIVED', data: {} },
239
- { type: 'NOTIFICATION_CLICKED', data: {} },
240
- { type: 'MESSAGE_REVOKED', data: {} },
241
- ];
242
-
243
- messages.forEach((msg) => {
244
- expect([
245
- 'MESSAGE_RECEIVED',
246
- 'NOTIFICATION_CLICKED',
247
- 'MESSAGE_REVOKED',
248
- ]).toContain(msg.type);
249
- expect(msg.data).toBeDefined();
250
- });
251
- });
252
- });
253
-
254
- describe('SubscriptionInfo 接口测试', () => {
255
- it('应该包含推送订阅的所有信息', () => {
256
- const mockSubscription = {
257
- endpoint: 'https://example.com/push',
258
- keys: {
259
- auth: 'mock-auth',
260
- p256dh: 'mock-p256dh',
261
- },
262
- } as PushSubscription;
263
-
264
- const subscriptionInfo: SubscriptionInfo = {
265
- subscription: mockSubscription,
266
- token: 'mock-token',
267
- auth: 'mock-auth',
268
- p256dh: 'mock-p256dh',
269
- };
270
-
271
- expect(subscriptionInfo.subscription).toBe(mockSubscription);
272
- expect(typeof subscriptionInfo.token).toBe('string');
273
- expect(typeof subscriptionInfo.auth).toBe('string');
274
- expect(typeof subscriptionInfo.p256dh).toBe('string');
275
- });
276
- });
277
-
278
- describe('EventResult 联合类型测试', () => {
279
- it('应该支持所有事件结果类型', () => {
280
- const messageReceived: EventResult = {
281
- data: {
282
- message: {} as Message,
283
- } as MessageReceivedResult,
284
- };
285
-
286
- const messageRevoked: EventResult = {
287
- data: {
288
- messageID: 'msg-123',
289
- } as MessageRevokedResult,
290
- };
291
-
292
- const notificationClicked: EventResult = {
293
- data: {
294
- ext: 'extension-data',
295
- } as MessageNotificationClickedResult,
296
- };
297
-
298
- expect(messageReceived.data).toBeDefined();
299
- expect(messageRevoked.data).toBeDefined();
300
- expect(notificationClicked.data).toBeDefined();
301
- });
302
- });
303
- });