@retailcrm/embed-ui-v1-testing 0.4.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.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # `@retailcrm/embed-ui-v1-testing`
2
+
3
+ Утилиты для упрощения тестирования логики JS-расширений RetailCRM
4
+
5
+ ## Установка
6
+
7
+ npm:
8
+
9
+ ```bash
10
+ npm i --save-dev @retailcrm/embed-ui-v1-testing
11
+ ```
12
+
13
+ yarn:
14
+ ```bash
15
+ yarn add -D @retailcrm/embed-ui-v1-testing
16
+ ```
@@ -0,0 +1,33 @@
1
+ import type {
2
+ ContextSchema,
3
+ EventHandler,
4
+ EventMap,
5
+ TypeOf,
6
+ FieldGetters,
7
+ } from '@retailcrm/embed-ui-v1-types/context'
8
+
9
+ import { retain } from '@remote-ui/rpc'
10
+ import { watch } from 'vue'
11
+
12
+ const keysOf = <T extends object>(o: T): (keyof T)[] => Object.keys(o) as (keyof T)[]
13
+
14
+ export const createHandler = <S extends ContextSchema>(id: string, getters: FieldGetters<S>) => {
15
+ type EventName = keyof EventMap<S>
16
+ type FieldName = keyof S
17
+
18
+ const map = keysOf(getters).reduce((eventMap, field) => {
19
+ eventMap[`change:${String(field)}` as EventName] = field as EventMap<S>[EventName]
20
+
21
+ return eventMap
22
+ }, {} as EventMap<S>)
23
+
24
+ return <E extends keyof EventMap<S>>(event: E, handler: EventHandler<S, E>) => {
25
+ if (!(event in map)) {
26
+ throw new Error(`[crm:embed:host] Event ${String(event)} is not supported in context ${id}`)
27
+ }
28
+
29
+ retain(handler)
30
+
31
+ watch(getters[map[event] as FieldName], handler as (payload: TypeOf<S[FieldName]>) => void)
32
+ }
33
+ }
package/lib/rpc.ts ADDED
@@ -0,0 +1,93 @@
1
+ class MessagePortPolyfill implements MessagePort {
2
+ onmessageerror: EventListener | null = null
3
+
4
+ otherPort!: MessagePortPolyfill
5
+ private listeners = new Set<EventListener>()
6
+
7
+ // MessagePort does not send messages unless it is started via start() or attaching .onmessage
8
+ // https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/start
9
+ private started = false
10
+ private _onmessage: EventListener | null = null
11
+
12
+ // If the port is not yet started, messages will be queued for sending.
13
+ private eventQueue: Event[] = []
14
+
15
+ get onmessage() {
16
+ return this._onmessage
17
+ }
18
+
19
+ set onmessage(listener: EventListener | null) {
20
+ // setting onmessage will start the port, even if the listener is null.
21
+ this._onmessage = listener
22
+ this.start()
23
+ }
24
+
25
+ dispatchEvent(event: Event) {
26
+ if (!this.started) {
27
+ this.eventQueue.push(event)
28
+ return true
29
+ }
30
+
31
+ if (this._onmessage) {
32
+ this._onmessage(event)
33
+ }
34
+
35
+ for (const listener of this.listeners) {
36
+ listener(event)
37
+ }
38
+
39
+ return true
40
+ }
41
+
42
+ postMessage(message: unknown) {
43
+ if (!this.otherPort) {
44
+ return
45
+ }
46
+
47
+ this.otherPort.dispatchEvent({ data: message } as unknown as Event)
48
+ }
49
+
50
+ addEventListener(type: string, listener: EventListener) {
51
+ if (type !== 'message') {
52
+ return
53
+ }
54
+
55
+ this.listeners.add(listener)
56
+ }
57
+
58
+ removeEventListener(type: string, listener: EventListener) {
59
+ if (type !== 'message') {
60
+ return
61
+ }
62
+
63
+ this.listeners.delete(listener)
64
+ }
65
+
66
+ start() {
67
+ this.started = true
68
+ while (this.eventQueue.length > 0) {
69
+ const event = this.eventQueue.shift()
70
+ if (event) {
71
+ this.dispatchEvent(event)
72
+ }
73
+ }
74
+ }
75
+
76
+ close() {
77
+ this.started = false
78
+ }
79
+ }
80
+
81
+ class MessageChannelPolyfill implements MessageChannel {
82
+ readonly port1: MessagePortPolyfill
83
+ readonly port2: MessagePortPolyfill
84
+
85
+ constructor() {
86
+ this.port1 = new MessagePortPolyfill()
87
+ this.port2 = new MessagePortPolyfill()
88
+ this.port1.otherPort = this.port2
89
+ this.port2.otherPort = this.port1
90
+ }
91
+ }
92
+
93
+ export { MessageChannelPolyfill as MessageChannel }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@retailcrm/embed-ui-v1-testing",
3
+ "type": "module",
4
+ "version": "0.4.5",
5
+ "license": "MIT",
6
+ "author": "RetailDriverLLC <integration@retailcrm.ru>",
7
+ "repository": "git@github.com:retailcrm/embed-ui.git",
8
+ "exports": {
9
+ ".": null,
10
+ "./*": "./*"
11
+ },
12
+ "peerDependencies": {
13
+ "@omnicajs/vue-remote": "^0.2.3",
14
+ "@remote-ui/rpc": "^1.4.5",
15
+ "vue": "^3.5"
16
+ },
17
+ "dependencies": {
18
+ "@retailcrm/embed-ui-v1-types": "^0.4.5"
19
+ }
20
+ }