@tencentcloud/web-push 1.0.2 → 1.0.3
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/README.md +102 -175
- package/dist/index.d.ts +259 -0
- package/{index.esm.js → dist/index.esm.js} +1118 -158
- package/dist/index.umd.js +1 -0
- package/dist/src/components/message-popup.d.ts +63 -0
- package/{src → dist/src}/core/web-push-sdk.d.ts +23 -1
- package/{src → dist/src}/index.d.ts +1 -0
- package/{src → dist/src}/types/inner.d.ts +2 -10
- package/dist/src/types/outer.d.ts +120 -0
- package/{src → dist/src}/utils/logger.d.ts +6 -0
- package/{src → dist/src}/utils/validator.d.ts +0 -13
- package/dist/sw.js +1 -0
- package/package.json +47 -9
- package/src/__tests__/index.test.ts +120 -0
- package/src/__tests__/integration.test.ts +285 -0
- package/src/__tests__/setup.ts +210 -0
- package/src/__tests__/types.test.ts +303 -0
- package/src/__tests__/web-push-sdk.test.ts +257 -0
- package/src/components/message-popup.ts +1007 -0
- package/src/core/event-emitter.ts +61 -0
- package/src/core/service-worker-manager.ts +614 -0
- package/src/core/web-push-sdk.ts +690 -0
- package/src/debug/GenerateTestUserSig.js +37 -0
- package/src/debug/index.d.ts +6 -0
- package/src/debug/index.js +1 -0
- package/src/debug/lib-generate-test-usersig-es.min.js +2 -0
- package/src/index.ts +9 -0
- package/src/service-worker/sw.ts +494 -0
- package/src/types/index.ts +2 -0
- package/src/types/inner.ts +44 -0
- package/src/types/outer.ts +142 -0
- package/src/utils/browser-support.ts +412 -0
- package/src/utils/logger.ts +66 -0
- package/src/utils/storage.ts +51 -0
- package/src/utils/validator.ts +267 -0
- package/CHANGELOG.md +0 -55
- package/index.d.ts +0 -110
- package/index.umd.js +0 -1
- package/src/types/outer.d.ts +0 -66
- package/sw.js +0 -1
- /package/{src → dist/src}/core/event-emitter.d.ts +0 -0
- /package/{src → dist/src}/core/service-worker-manager.d.ts +0 -0
- /package/{src → dist/src}/service-worker/sw.d.ts +0 -0
- /package/{src → dist/src}/types/index.d.ts +0 -0
- /package/{src → dist/src}/utils/browser-support.d.ts +0 -0
- /package/{src → dist/src}/utils/storage.d.ts +0 -0
|
@@ -3,12 +3,14 @@ export declare class WebPushSDK implements IWebPushSDK {
|
|
|
3
3
|
static instance: WebPushSDK;
|
|
4
4
|
private eventEmitter;
|
|
5
5
|
private serviceWorkerManager;
|
|
6
|
+
private messagePopup;
|
|
6
7
|
private isRegistered;
|
|
7
8
|
private registrationID;
|
|
8
9
|
private chat;
|
|
9
10
|
private SDKAppID;
|
|
10
11
|
private appKey;
|
|
11
12
|
private vapidPublicKey;
|
|
13
|
+
private pendingMessages;
|
|
12
14
|
EVENT: typeof EVENT;
|
|
13
15
|
VERSION: string;
|
|
14
16
|
constructor();
|
|
@@ -16,16 +18,36 @@ export declare class WebPushSDK implements IWebPushSDK {
|
|
|
16
18
|
registerPush(options?: RegisterPushOptions): Promise<string>;
|
|
17
19
|
unRegisterPush(): Promise<boolean>;
|
|
18
20
|
addPushListener(eventName: EVENT, listener: Function): string;
|
|
21
|
+
/**
|
|
22
|
+
* 内部方法:向 Service Worker 发送日志级别配置
|
|
23
|
+
* @param logLevel 日志级别 0-4
|
|
24
|
+
*/
|
|
25
|
+
private sendLogLevelToServiceWorker;
|
|
19
26
|
removePushListener(eventName: EVENT, listener: Function): boolean;
|
|
20
27
|
private checkBrowserSupport;
|
|
21
28
|
private requestNotificationPermission;
|
|
22
|
-
private
|
|
29
|
+
private pushLogin;
|
|
30
|
+
private onMessageReceived;
|
|
31
|
+
private onMessageRevoked;
|
|
32
|
+
private addChatListener;
|
|
33
|
+
private removeChatListener;
|
|
23
34
|
private getSystemPermissionMessage;
|
|
24
35
|
private showSystemPermissionAlert;
|
|
25
36
|
private getBrowserInstType;
|
|
26
37
|
private setToken;
|
|
27
38
|
private initializeBrowserCompatibility;
|
|
39
|
+
private setupVisibilityChangeListener;
|
|
28
40
|
private setupInternalListeners;
|
|
29
41
|
private pushStatistics;
|
|
30
42
|
private clearState;
|
|
43
|
+
/**
|
|
44
|
+
* 向 service-worker 发送通知消息,使用与 push 事件相同的数据格式
|
|
45
|
+
* @param webpushInfo webpush 信息,格式与 SW push 事件接收的数据一致
|
|
46
|
+
*/
|
|
47
|
+
private sendNotificationToServiceWorker;
|
|
48
|
+
/**
|
|
49
|
+
* 向 service-worker 发送消息撤回请求
|
|
50
|
+
* @param messageID 要撤回的消息ID
|
|
51
|
+
*/
|
|
52
|
+
private sendMessageRevokeToServiceWorker;
|
|
31
53
|
}
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
messageID: string;
|
|
3
|
-
title: string;
|
|
4
|
-
body: string;
|
|
5
|
-
icon?: string;
|
|
6
|
-
tag?: string;
|
|
7
|
-
data?: any;
|
|
8
|
-
timestamp: number;
|
|
9
|
-
}
|
|
1
|
+
import { NotificationMessage } from "./outer";
|
|
10
2
|
export interface NotificationClickData {
|
|
11
|
-
notification:
|
|
3
|
+
notification: NotificationMessage;
|
|
12
4
|
action?: string;
|
|
13
5
|
}
|
|
14
6
|
export interface StatisticsData {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export type LogLevel = 0 | 1 | 2 | 3 | 4;
|
|
2
|
+
export declare enum Placement {
|
|
3
|
+
CENTER = 0,// 中间
|
|
4
|
+
TOP_LEFT = 1,// 左上
|
|
5
|
+
TOP_CENTER = 2,// 上中
|
|
6
|
+
TOP_RIGHT = 3,// 右上
|
|
7
|
+
MIDDLE_RIGHT = 4,// 右中
|
|
8
|
+
BOTTOM_RIGHT = 5,// 右下
|
|
9
|
+
BOTTOM_CENTER = 6,// 下中
|
|
10
|
+
BOTTOM_LEFT = 7,// 左下
|
|
11
|
+
MIDDLE_LEFT = 8
|
|
12
|
+
}
|
|
13
|
+
export interface WebPushSDK {
|
|
14
|
+
registerPush(options?: RegisterPushOptions): Promise<any>;
|
|
15
|
+
unRegisterPush(): Promise<any>;
|
|
16
|
+
addPushListener(eventName: EVENT, listener: (data: EventResult) => void): any;
|
|
17
|
+
removePushListener(eventName: EVENT, listener: (data: EventResult) => void): any;
|
|
18
|
+
}
|
|
19
|
+
export interface RegisterPushOptions {
|
|
20
|
+
SDKAppID: number;
|
|
21
|
+
appKey: string;
|
|
22
|
+
userID: string;
|
|
23
|
+
serviceWorkerPath?: string;
|
|
24
|
+
chat?: any;
|
|
25
|
+
/**
|
|
26
|
+
* 日志级别:
|
|
27
|
+
* 0 - 普通级别,日志量较多,接入时建议使用
|
|
28
|
+
* 1 - release级别,SDK 输出关键信息,生产环境时建议使用(默认)
|
|
29
|
+
* 2 - 告警级别,SDK 只输出告警和错误级别的日志
|
|
30
|
+
* 3 - 错误级别,SDK 只输出错误级别的日志
|
|
31
|
+
* 4 - 无日志级别,SDK 将不打印任何日志
|
|
32
|
+
*/
|
|
33
|
+
logLevel?: LogLevel;
|
|
34
|
+
}
|
|
35
|
+
export declare enum EVENT {
|
|
36
|
+
MESSAGE_RECEIVED = "message_received",
|
|
37
|
+
MESSAGE_REVOKED = "message_revoked",
|
|
38
|
+
NOTIFICATION_CLICKED = "notification_clicked",
|
|
39
|
+
CUSTOM_MESSAGE_RECEIVED = "custom_message_received"
|
|
40
|
+
}
|
|
41
|
+
export interface NotificationMessage {
|
|
42
|
+
messageID: string;
|
|
43
|
+
title: string;
|
|
44
|
+
body: string;
|
|
45
|
+
icon?: string;
|
|
46
|
+
tag?: string;
|
|
47
|
+
data?: any;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
}
|
|
50
|
+
export interface StandardMessage {
|
|
51
|
+
id: string;
|
|
52
|
+
MsgType: 'standard';
|
|
53
|
+
MsgContent: {
|
|
54
|
+
Text: {
|
|
55
|
+
Title: string;
|
|
56
|
+
Desc: string;
|
|
57
|
+
};
|
|
58
|
+
Image?: {
|
|
59
|
+
URL: string;
|
|
60
|
+
LinkURL: string;
|
|
61
|
+
};
|
|
62
|
+
Close: 0 | 1;
|
|
63
|
+
Placement?: Placement;
|
|
64
|
+
Duration?: number;
|
|
65
|
+
Button?: Array<{
|
|
66
|
+
Text: string;
|
|
67
|
+
Icon?: string;
|
|
68
|
+
Url: string;
|
|
69
|
+
}>;
|
|
70
|
+
};
|
|
71
|
+
Ext?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface HtmlMessage {
|
|
74
|
+
id: string;
|
|
75
|
+
MsgType: 'html';
|
|
76
|
+
MsgContent: {
|
|
77
|
+
Placement?: Placement;
|
|
78
|
+
Duration?: number;
|
|
79
|
+
Html: string;
|
|
80
|
+
};
|
|
81
|
+
Ext?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface CustomMessage {
|
|
84
|
+
id: string;
|
|
85
|
+
MsgType: 'custom';
|
|
86
|
+
MsgContent: {
|
|
87
|
+
Data: string | object;
|
|
88
|
+
};
|
|
89
|
+
Ext?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface WebPushInfo {
|
|
92
|
+
Title: string;
|
|
93
|
+
Desc: string;
|
|
94
|
+
Icon: string;
|
|
95
|
+
Image: string;
|
|
96
|
+
URL: string;
|
|
97
|
+
}
|
|
98
|
+
export interface WebPushExt {
|
|
99
|
+
WebpushReportUrl: string;
|
|
100
|
+
OnlineClickExt: string;
|
|
101
|
+
TaskId: string;
|
|
102
|
+
}
|
|
103
|
+
export type PushMessage = StandardMessage | HtmlMessage | CustomMessage;
|
|
104
|
+
export interface MessageReceivedData {
|
|
105
|
+
content: string;
|
|
106
|
+
info: WebPushInfo;
|
|
107
|
+
extension: WebPushExt;
|
|
108
|
+
}
|
|
109
|
+
export interface MessageReceivedResult {
|
|
110
|
+
message: PushMessage | NotificationMessage;
|
|
111
|
+
}
|
|
112
|
+
export interface MessageRevokedResult {
|
|
113
|
+
messageID: String;
|
|
114
|
+
}
|
|
115
|
+
export interface MessageNotificationClickedResult {
|
|
116
|
+
ext: String;
|
|
117
|
+
}
|
|
118
|
+
export interface EventResult {
|
|
119
|
+
data: MessageReceivedResult | MessageRevokedResult | MessageNotificationClickedResult;
|
|
120
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { LogLevel } from '../types/outer';
|
|
1
2
|
export declare class Logger {
|
|
2
3
|
private static instance;
|
|
4
|
+
private logLevel;
|
|
3
5
|
private constructor();
|
|
4
6
|
static getInstance(): Logger;
|
|
7
|
+
setLogLevel(level: LogLevel): void;
|
|
8
|
+
getLogLevel(): LogLevel;
|
|
9
|
+
private shouldLog;
|
|
5
10
|
log(message: string, ...args: any[]): void;
|
|
6
11
|
warn(message: string, ...args: any[]): void;
|
|
7
12
|
error(message: string, ...args: any[]): void;
|
|
8
13
|
info(message: string, ...args: any[]): void;
|
|
14
|
+
debug(message: string, ...args: any[]): void;
|
|
9
15
|
}
|
|
10
16
|
export declare const logger: Logger;
|
|
@@ -37,21 +37,8 @@ export declare class Validator {
|
|
|
37
37
|
static validateEventType(eventType: any): void;
|
|
38
38
|
static validateListener(listener: any): void;
|
|
39
39
|
static validateRegisterPushOptions(options: any): void;
|
|
40
|
-
static validatePushMessage(message: any): void;
|
|
41
|
-
/**
|
|
42
|
-
* Validate URL format
|
|
43
|
-
*/
|
|
44
|
-
static validateURL(url: any, fieldName?: string): void;
|
|
45
40
|
/**
|
|
46
41
|
* Validate Service Worker path
|
|
47
42
|
*/
|
|
48
43
|
static validateServiceWorkerPath(path: any): void;
|
|
49
44
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Parameter validation decorator
|
|
52
|
-
*/
|
|
53
|
-
export declare function validateParams(schema: ValidationSchema): (_target: any, _propertyName: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
54
|
-
/**
|
|
55
|
-
* Single parameter validation decorator
|
|
56
|
-
*/
|
|
57
|
-
export declare function validateParam(paramIndex: number, rule: ValidationRule): (_target: any, _propertyName: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(){"use strict";let t=1;function e(e){return 4!==t&&e>=t}function a(t,...a){e(1)&&console.log(`[WebPush SW] ${t}`,...a)}function i(t,...a){e(2)&&console.warn(`[WebPush SW] ${t}`,...a)}function n(t,...a){e(3)&&console.error(`[WebPush SW] ${t}`,...a)}async function o(t,e={}){const{shouldReport:a=!0,clickEventType:i=2}=e,n={messageID:t.id||Date.now().toString(36)+Math.random().toString(36).substring(2),title:t.title||"New Message",body:t.desc||"You have a new message",icon:t.icon||"",tag:t.tag||t?.id?.slice(-100)||"push-"+Date.now()+"-"+Math.random().toString(36).substring(2,7),data:{url:t.url,image:t.image,rptExt:t.rptExt,rptURL:t.rptURL,clickEventType:i},timestamp:Date.now()},o=self.registration.showNotification(n.title,{body:n.body,icon:n.icon,image:t.image,tag:n.tag,data:n,requireInteraction:!1}),l=r({type:"MESSAGE_RECEIVED",data:s(n)}),d=a&&t.rptURL&&t.rptExt?c({id:t.id,rptURL:t.rptURL,rptExt:t.rptExt,eventType:1}):Promise.resolve();await Promise.all([o,l,d])}function s(t){return{messageID:t.messageID,title:t.title,body:t.body,icon:t.icon,tag:t.tag,data:{url:t.data?.url,image:t.data?.image},timestamp:t.timestamp}}async function r(t){try{(await self.clients.matchAll({includeUncontrolled:!0,type:"window"})).forEach(e=>{e.postMessage(t)})}catch(e){n("Failed to send message to clients",e)}}async function c(t){try{if(!t.rptURL||!t.rptExt)return void i("Missing rptURL or rptExt, skipping report");const e={webpushEvents:[{id:t.id,EventType:t.eventType||1,EventTime:Math.floor(Date.now()/1e3),rptExt:t.rptExt}]};a("Reporting WebPush event",{rptURL:t.rptURL,reportData:e});const n=await fetch(t.rptURL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});n.ok?a("WebPush event reported successfully"):i("Failed to report WebPush event",n.status,n.statusText)}catch(e){n("Error reporting WebPush event",e)}}self.addEventListener("install",t=>{a("Service Worker installing..."),self.skipWaiting()}),self.addEventListener("activate",t=>{a("Service Worker activating..."),t.waitUntil(self.clients.claim())}),self.addEventListener("push",t=>{if(a("Push message received",t),t.data)try{const e=function(t){if(!t)throw new Error("No push data available");try{const e=t.json();return a("Push message data (JSON):",e),e}catch{const e=t.text();return a("Push message data (Text):",e),{id:"",title:"WebPush Notification",desc:e||"You have a new message",url:"/",icon:"",tag:"",image:"",rptExt:"",rptURL:""}}}(t.data);t.waitUntil(o(e))}catch(e){n("Failed to process push message",e),t.waitUntil(self.registration.showNotification("WebPush Notification",{body:"You have a new message",tag:"fallback"}))}else i("Push message has no data")}),self.addEventListener("notificationclick",t=>{a("Notification clicked",t);const e=t.notification,o=t.action,l=e.data;if(e.close(),"close"===o)return;const d=r({type:"NOTIFICATION_CLICKED",data:{notification:s(l),action:o}}),u=async function(t="/"){try{a("Attempting to open or focus window with URL:",t);const n=await self.clients.matchAll({type:"window",includeUncontrolled:!0});let o;a("Found clients:",n.length);try{o=t.startsWith("http://")||t.startsWith("https://")?t:new URL(t,self.location.origin).href}catch(e){i("Invalid URL, using origin:",t,e),o=self.location.origin}a("Full target URL:",o);for(const t of n)if(t.url===o&&"focus"in t)return void(await t.focus());self.clients.openWindow&&await self.clients.openWindow(o)}catch(e){n("Failed to open or focus window",e)}}(l?.data?.url||"/"),p=l?.data?.clickEventType||2,f=l?.data?.rptURL&&l?.data?.rptExt?c({id:l.messageID,rptURL:l.data.rptURL,rptExt:l.data.rptExt,eventType:p}):Promise.resolve();t.waitUntil(Promise.all([d,u,f]))}),self.addEventListener("notificationclose",t=>{a("Notification closed",t)}),self.addEventListener("message",e=>{a("Message received from main thread",e.data);const{type:i,payload:s}=e.data;switch(i){case"SHOW_NOTIFICATION":!async function(t){try{const{eventType:e,data:i,options:n}=t;a("Handling show notification request",{eventType:e,data:i,options:n}),await self.registration.showNotification(n.title,{body:n.body,icon:n.icon,badge:n.badge,tag:n.tag,requireInteraction:n.requireInteraction,silent:n.silent,data:n.data}),a("Notification shown successfully",n.title)}catch(e){n("Failed to handle show notification",e)}}(s);break;case"PROCESS_WEBPUSH_DATA":!async function(t){try{a("Handling webpush data from main thread",t),await o(t,{shouldReport:!1,clickEventType:3}),a("WebPush notification processed successfully")}catch(e){n("Failed to handle webpush data",e);try{await self.registration.showNotification("WebPush Notification",{body:"You have a new message",tag:"fallback"})}catch(i){n("Failed to show fallback notification",i)}}}(s);break;case"REVOKE_MESSAGE":!async function(t){try{(await self.registration.getNotifications()).forEach(e=>{e.data&&e.data.messageID===t&&e.close()}),await r({type:"MESSAGE_REVOKED",data:{messageID:t}})}catch(e){n("Failed to handle message revocation",e)}}(s.messageID);break;case"SET_LOG_LEVEL":l=s.logLevel,t=l,a("Log level updated to:",l);break;case"REPORT_WEBPUSH_EVENT":c(s)}var l}),self.addEventListener("error",t=>{n("Service Worker error",t.error)}),self.addEventListener("unhandledrejection",t=>{n("Service Worker unhandled promise rejection",t.reason)})}();
|
package/package.json
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tencentcloud/web-push",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Tencent Cloud Web Push SDK - Service Worker-based web push notification service",
|
|
5
|
-
"main": "index.umd.js",
|
|
6
|
-
"module": "index.esm.js",
|
|
7
|
-
"types": "index.d.ts",
|
|
5
|
+
"main": "dist/index.umd.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./index.d.ts",
|
|
11
|
-
"import": "./index.esm.js",
|
|
12
|
-
"require": "./index.umd.js"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.esm.js",
|
|
12
|
+
"require": "./dist/index.umd.js"
|
|
13
13
|
},
|
|
14
|
-
"./sw": "./sw.js"
|
|
14
|
+
"./sw": "./dist/sw.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
18
19
|
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "vite",
|
|
22
|
+
"build": "rm -rf dist && vite build && npm run build:sw && npm run build:types",
|
|
23
|
+
"build:sw": "vite build --config vite.sw.config.ts",
|
|
24
|
+
"build:types": "tsc --project tsconfig.build.json",
|
|
25
|
+
"build:release": "node scripts/build-release.js",
|
|
26
|
+
"preview": "vite preview",
|
|
27
|
+
"test": "jest --verbose",
|
|
28
|
+
"test:coverage": "jest --coverage",
|
|
29
|
+
"lint": "eslint src --ext .ts,.js",
|
|
30
|
+
"lint:fix": "eslint src --ext .ts,.js --fix",
|
|
31
|
+
"format": "prettier --write \"src/**/*.{ts,js,json,md}\"",
|
|
32
|
+
"format:check": "prettier --check \"src/**/*.{ts,js,json,md}\"",
|
|
33
|
+
"type-check": "tsc --noEmit",
|
|
34
|
+
"pre-commit": "lint-staged",
|
|
35
|
+
"prepare": "husky install",
|
|
36
|
+
"prepublish": "npm run build && npm run lint && npm run build:release",
|
|
37
|
+
"publish": "cd dist && npm publish --access public"
|
|
38
|
+
},
|
|
19
39
|
"keywords": [
|
|
20
40
|
"web-push",
|
|
21
41
|
"service-worker",
|
|
@@ -24,6 +44,24 @@
|
|
|
24
44
|
],
|
|
25
45
|
"author": "Tencent Cloud",
|
|
26
46
|
"license": "MIT",
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@babel/preset-env": "^7.28.3",
|
|
49
|
+
"@types/jest": "^29.5.5",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
|
51
|
+
"@typescript-eslint/parser": "^8.46.1",
|
|
52
|
+
"chalk": "^5.6.2",
|
|
53
|
+
"eslint": "^8.50.0",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"jest": "^29.7.0",
|
|
56
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
57
|
+
"lint-staged": "^16.2.4",
|
|
58
|
+
"prettier": "^3.6.2",
|
|
59
|
+
"terser": "^5.44.0",
|
|
60
|
+
"ts-jest": "^29.1.1",
|
|
61
|
+
"typescript": "^5.2.2",
|
|
62
|
+
"vite": "^4.4.9",
|
|
63
|
+
"vite-plugin-dts": "^3.6.0"
|
|
64
|
+
},
|
|
27
65
|
"peerDependencies": {
|
|
28
66
|
"@tencentcloud/lite-chat": "^4.2.0"
|
|
29
67
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主入口文件测试
|
|
3
|
+
*/
|
|
4
|
+
import webPush, { webPush as namedExport, EVENT } from '../index';
|
|
5
|
+
import type { RegisterPushOptions } from '../index';
|
|
6
|
+
|
|
7
|
+
describe('主入口文件测试', () => {
|
|
8
|
+
describe('导出测试', () => {
|
|
9
|
+
it('应该导出默认的 webPush 实例', () => {
|
|
10
|
+
expect(webPush).toBeDefined();
|
|
11
|
+
expect(typeof webPush.registerPush).toBe('function');
|
|
12
|
+
expect(typeof webPush.unRegisterPush).toBe('function');
|
|
13
|
+
expect(typeof webPush.addPushListener).toBe('function');
|
|
14
|
+
expect(typeof webPush.removePushListener).toBe('function');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('应该导出命名的 webPush 实例', () => {
|
|
18
|
+
expect(namedExport).toBeDefined();
|
|
19
|
+
expect(namedExport).toBe(webPush);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('应该导出 EVENT 常量', () => {
|
|
23
|
+
expect(EVENT).toBeDefined();
|
|
24
|
+
expect(EVENT.MESSAGE_RECEIVED).toBe('message_received');
|
|
25
|
+
expect(EVENT.MESSAGE_REVOKED).toBe('message_revoked');
|
|
26
|
+
expect(EVENT.NOTIFICATION_CLICKED).toBe('notification_clicked');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('应该通过实例获取版本号', () => {
|
|
30
|
+
expect(webPush.VERSION).toBeDefined();
|
|
31
|
+
expect(typeof webPush.VERSION).toBe('string');
|
|
32
|
+
expect(webPush.VERSION).toBe('0.1.0');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('应该导出正确的 TypeScript 类型', () => {
|
|
36
|
+
// 这些测试主要是为了确保类型导出正确,在编译时会检查
|
|
37
|
+
const options: RegisterPushOptions = {
|
|
38
|
+
SDKAppID: 123456,
|
|
39
|
+
appKey: 'test-key',
|
|
40
|
+
userID: 'test-user',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const eventType = EVENT.MESSAGE_RECEIVED;
|
|
44
|
+
|
|
45
|
+
const message = {
|
|
46
|
+
messageID: 'test-id',
|
|
47
|
+
title: 'Test Title',
|
|
48
|
+
body: 'Test Body',
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const clickData = {
|
|
53
|
+
notification: message,
|
|
54
|
+
action: 'default',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// 类型检查通过即可
|
|
58
|
+
expect(options).toBeDefined();
|
|
59
|
+
expect(eventType).toBeDefined();
|
|
60
|
+
expect(message).toBeDefined();
|
|
61
|
+
expect(clickData).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('单例一致性测试', () => {
|
|
66
|
+
it('默认导出和命名导出应该是同一个实例', () => {
|
|
67
|
+
expect(webPush).toBe(namedExport);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('多次导入应该返回同一个实例', () => {
|
|
71
|
+
// 重新导入模块
|
|
72
|
+
jest.resetModules();
|
|
73
|
+
const { default: webPush1, webPush: webPush2 } = require('../index');
|
|
74
|
+
|
|
75
|
+
expect(webPush1).toBe(webPush2);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('接口一致性测试', () => {
|
|
80
|
+
it('实例应该实现 IWebPushSDK 接口', () => {
|
|
81
|
+
// 检查所有必需的方法是否存在
|
|
82
|
+
expect(typeof webPush.registerPush).toBe('function');
|
|
83
|
+
expect(typeof webPush.unRegisterPush).toBe('function');
|
|
84
|
+
expect(typeof webPush.addPushListener).toBe('function');
|
|
85
|
+
expect(typeof webPush.removePushListener).toBe('function');
|
|
86
|
+
expect(webPush.EVENT).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('EVENT 属性应该与导出的 EVENT 常量一致', () => {
|
|
90
|
+
expect(webPush.EVENT).toEqual(EVENT);
|
|
91
|
+
expect(webPush.EVENT.MESSAGE_RECEIVED).toBe(EVENT.MESSAGE_RECEIVED);
|
|
92
|
+
expect(webPush.EVENT.MESSAGE_REVOKED).toBe(EVENT.MESSAGE_REVOKED);
|
|
93
|
+
expect(webPush.EVENT.NOTIFICATION_CLICKED).toBe(
|
|
94
|
+
EVENT.NOTIFICATION_CLICKED
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('模块稳定性测试', () => {
|
|
100
|
+
it('应该能够安全地多次导入', () => {
|
|
101
|
+
expect(() => {
|
|
102
|
+
require('../index');
|
|
103
|
+
require('../index');
|
|
104
|
+
require('../index');
|
|
105
|
+
}).not.toThrow();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('导出的对象应该是不可变的关键属性', () => {
|
|
109
|
+
// 验证 EVENT 对象的基本属性
|
|
110
|
+
expect(EVENT.MESSAGE_RECEIVED).toBe('message_received');
|
|
111
|
+
expect(EVENT.MESSAGE_REVOKED).toBe('message_revoked');
|
|
112
|
+
expect(EVENT.NOTIFICATION_CLICKED).toBe('notification_clicked');
|
|
113
|
+
|
|
114
|
+
// 验证 EVENT 对象包含所有必需的属性
|
|
115
|
+
expect(Object.keys(EVENT)).toContain('MESSAGE_RECEIVED');
|
|
116
|
+
expect(Object.keys(EVENT)).toContain('MESSAGE_REVOKED');
|
|
117
|
+
expect(Object.keys(EVENT)).toContain('NOTIFICATION_CLICKED');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|