Skip to content

Commit 9a92de8

Browse files
committed
feat(container): add registerApi for H5 custom API registration
- Add apiRegistry map, registerApi() and invokeApi() to MiniApp - Update bridge.js dispatch to use invokeApi() (registry-first, fallback to built-in) - Add test infrastructure and 7 unit tests for the registration mechanism
1 parent f9a56ba commit 9a92de8

File tree

4 files changed

+135
-2
lines changed

4 files changed

+135
-2
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
3+
/**
4+
* Test the registerApi/invokeApi mechanism in isolation.
5+
* We replicate the logic from MiniApp to avoid importing the full class
6+
* which has heavy DOM/Worker dependencies.
7+
*/
8+
function createMiniAppStub() {
9+
const app = {
10+
apiRegistry: {},
11+
12+
registerApi(name, handler) {
13+
this.apiRegistry[name] = handler
14+
},
15+
16+
invokeApi(name, params) {
17+
const handler = this.apiRegistry[name]
18+
if (handler) {
19+
handler.call(this, params)
20+
}
21+
else if (typeof this[name] === 'function') {
22+
this[name](params)
23+
}
24+
},
25+
}
26+
return app
27+
}
28+
29+
describe('MiniApp registerApi', () => {
30+
it('should invoke a registered custom API handler', () => {
31+
const app = createMiniAppStub()
32+
const handler = vi.fn()
33+
34+
app.registerApi('getQdLocation', handler)
35+
app.invokeApi('getQdLocation', { foo: 'bar' })
36+
37+
expect(handler).toHaveBeenCalledWith({ foo: 'bar' })
38+
})
39+
40+
it('should fall back to built-in method when no custom handler registered', () => {
41+
const app = createMiniAppStub()
42+
app.request = vi.fn()
43+
44+
app.invokeApi('request', { url: 'https://example.com' })
45+
46+
expect(app.request).toHaveBeenCalledWith({ url: 'https://example.com' })
47+
})
48+
49+
it('should prefer custom handler over built-in method', () => {
50+
const app = createMiniAppStub()
51+
const customHandler = vi.fn()
52+
app.request = vi.fn()
53+
54+
app.registerApi('request', customHandler)
55+
app.invokeApi('request', { url: 'test' })
56+
57+
expect(customHandler).toHaveBeenCalledWith({ url: 'test' })
58+
expect(app.request).not.toHaveBeenCalled()
59+
})
60+
61+
it('should not throw when invoking an unknown API', () => {
62+
const app = createMiniAppStub()
63+
64+
expect(() => app.invokeApi('nonExistentApi', {})).not.toThrow()
65+
})
66+
67+
it('should support registering multiple custom APIs', () => {
68+
const app = createMiniAppStub()
69+
const handler1 = vi.fn()
70+
const handler2 = vi.fn()
71+
72+
app.registerApi('customApi1', handler1)
73+
app.registerApi('customApi2', handler2)
74+
75+
app.invokeApi('customApi1', { a: 1 })
76+
app.invokeApi('customApi2', { b: 2 })
77+
78+
expect(handler1).toHaveBeenCalledWith({ a: 1 })
79+
expect(handler2).toHaveBeenCalledWith({ b: 2 })
80+
})
81+
82+
it('should allow overwriting a registered handler', () => {
83+
const app = createMiniAppStub()
84+
const handler1 = vi.fn()
85+
const handler2 = vi.fn()
86+
87+
app.registerApi('myApi', handler1)
88+
app.registerApi('myApi', handler2)
89+
app.invokeApi('myApi', {})
90+
91+
expect(handler1).not.toHaveBeenCalled()
92+
expect(handler2).toHaveBeenCalled()
93+
})
94+
95+
it('should call handler with app as this context', () => {
96+
const app = createMiniAppStub()
97+
let thisRef = null
98+
99+
app.registerApi('checkThis', function () {
100+
thisRef = this
101+
})
102+
app.invokeApi('checkThis', {})
103+
104+
expect(thisRef).toBe(app)
105+
})
106+
})

fe/packages/container/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"dev": "vite",
88
"build": "vite build",
99
"preview": "vite preview",
10-
"serve": "qrcode --small \"http://$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}'):9966\" && http-server ./dist/ -c-1 -p 9966 -g"
10+
"serve": "qrcode --small \"http://$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}'):9966\" && http-server ./dist/ -c-1 -p 9966 -g",
11+
"test": "vitest run",
12+
"test:dev": "vitest"
1113
},
1214
"dependencies": {
1315
"@dimina/common": "workspace:^",

fe/packages/container/src/core/bridge.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export class Bridge {
9999
if (type === 'invokeAPI') {
100100
const { name, params } = body
101101
// parent 是 miniApp 对象
102-
this.parent[name]?.(params)
102+
this.parent.invokeApi(name, params)
103103
}
104104
}
105105
}

fe/packages/container/src/pages/miniApp/miniApp.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@ export class MiniApp {
2424
timer: null,
2525
}
2626
this.color = null
27+
this.apiRegistry = {}
28+
}
29+
30+
/**
31+
* Register a custom API handler
32+
* @param {string} name API name
33+
* @param {function} handler Handler function receiving (params)
34+
*/
35+
registerApi(name, handler) {
36+
this.apiRegistry[name] = handler
37+
}
38+
39+
/**
40+
* Invoke an API by name, checking registry first then built-in methods
41+
* @param {string} name API name
42+
* @param {object} params API parameters
43+
*/
44+
invokeApi(name, params) {
45+
const handler = this.apiRegistry[name]
46+
if (handler) {
47+
handler.call(this, params)
48+
}
49+
else if (typeof this[name] === 'function') {
50+
this[name](params)
51+
}
2752
}
2853

2954
viewDidLoad() {

0 commit comments

Comments
 (0)