@api-client/ui 0.1.0 → 0.1.2
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/build/src/core/Activity.d.ts +3 -3
- package/build/src/core/Activity.d.ts.map +1 -1
- package/build/src/core/Activity.js +8 -7
- package/build/src/core/Activity.js.map +1 -1
- package/build/src/core/ActivityManager.d.ts +9 -0
- package/build/src/core/ActivityManager.d.ts.map +1 -1
- package/build/src/core/ActivityManager.js +57 -12
- package/build/src/core/ActivityManager.js.map +1 -1
- package/build/src/core/Application.d.ts +1 -0
- package/build/src/core/Application.d.ts.map +1 -1
- package/build/src/core/Application.js +3 -0
- package/build/src/core/Application.js.map +1 -1
- package/build/src/core/Fragment.d.ts +9 -3
- package/build/src/core/Fragment.d.ts.map +1 -1
- package/build/src/core/Fragment.js +17 -8
- package/build/src/core/Fragment.js.map +1 -1
- package/build/src/core/FragmentManager.d.ts +17 -0
- package/build/src/core/FragmentManager.d.ts.map +1 -1
- package/build/src/core/FragmentManager.js +58 -2
- package/build/src/core/FragmentManager.js.map +1 -1
- package/build/src/core/renderer/Renderer.d.ts +4 -1
- package/build/src/core/renderer/Renderer.d.ts.map +1 -1
- package/build/src/core/renderer/Renderer.js +3 -0
- package/build/src/core/renderer/Renderer.js.map +1 -1
- package/build/src/elements/data-table/DataTable.d.ts +7 -0
- package/build/src/elements/data-table/DataTable.d.ts.map +1 -1
- package/build/src/elements/data-table/DataTable.js +8 -0
- package/build/src/elements/data-table/DataTable.js.map +1 -1
- package/package.json +1 -1
- package/src/core/Activity.ts +8 -7
- package/src/core/ActivityManager.ts +58 -12
- package/src/core/Application.ts +4 -0
- package/src/core/Fragment.ts +18 -8
- package/src/core/FragmentManager.ts +61 -3
- package/src/core/renderer/Renderer.ts +4 -1
- package/src/elements/data-table/DataTable.ts +7 -0
- package/test/core/activity.spec.ts +235 -2
- package/test/core/activity_manager.spec.ts +544 -0
- package/test/core/application.spec.ts +218 -0
- package/test/core/fragment.spec.ts +472 -0
- package/test/core/fragment_manager.spec.ts +404 -0
- package/web-test-runner.config.js +1 -1
|
@@ -3,24 +3,39 @@ import { Activity } from '../../src/core/Activity.js'
|
|
|
3
3
|
import { Application } from '../../src/core/Application.js'
|
|
4
4
|
import { IntentResult, ActivityState } from '../../src/core/ActivityManager.js'
|
|
5
5
|
import { fixture, html } from '@open-wc/testing'
|
|
6
|
+
import { EventTypes } from '../../src/events/EventTypes.js'
|
|
6
7
|
import sinon from 'sinon'
|
|
8
|
+
import { nothing } from 'lit'
|
|
9
|
+
import { Fragment } from '../../src/core/Fragment.js'
|
|
10
|
+
import type { ActivityDetail } from '../../src/events/IntentEvents.js'
|
|
7
11
|
|
|
8
12
|
class TestActivity extends Activity {
|
|
9
13
|
static override action = 'test-activity'
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
class TestActivity2 extends Activity {
|
|
17
|
+
static override action = 'test-activity2'
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
class TestApplication extends Application {
|
|
13
21
|
override async onStart(): Promise<void> {
|
|
14
22
|
this.manager.registerActivity(TestActivity.action, TestActivity)
|
|
23
|
+
this.manager.registerActivity(TestActivity2.action, TestActivity2)
|
|
24
|
+
// The creation below is for tests that require an activity to be present in the manager
|
|
25
|
+
// e.g. for setResult, getApplication, getActivity, hasRequestCode, onActivityResult
|
|
26
|
+
// For other tests, a new TestActivity is created directly.
|
|
27
|
+
// This helps isolate tests for lifecycle events from manager interactions.
|
|
15
28
|
await this.manager.createActivity({ action: TestActivity.action, data: { test: true } })
|
|
16
29
|
}
|
|
17
30
|
}
|
|
18
31
|
|
|
32
|
+
class TestFragment extends Fragment {}
|
|
33
|
+
|
|
19
34
|
async function basicFixture(): Promise<HTMLElement> {
|
|
20
35
|
return fixture(html`<div id="app"></div>`)
|
|
21
36
|
}
|
|
22
37
|
|
|
23
|
-
describe('Events', () => {
|
|
38
|
+
describe('Activity Lifecycle and Events', () => {
|
|
24
39
|
let application: Application
|
|
25
40
|
let activity: Activity
|
|
26
41
|
|
|
@@ -28,6 +43,7 @@ describe('Events', () => {
|
|
|
28
43
|
const renderRoot = await basicFixture()
|
|
29
44
|
application = new TestApplication(renderRoot)
|
|
30
45
|
activity = new TestActivity(application)
|
|
46
|
+
// Note: application.onStart() is not called here to isolate Activity's own lifecycle methods.
|
|
31
47
|
})
|
|
32
48
|
|
|
33
49
|
it('dispatches the activity:create event', async () => {
|
|
@@ -79,6 +95,12 @@ describe('Events', () => {
|
|
|
79
95
|
assert.isTrue(spy.calledOnce)
|
|
80
96
|
})
|
|
81
97
|
|
|
98
|
+
it('calls manager.onDestroy when activity is destroyed', async () => {
|
|
99
|
+
const spy = sinon.spy(activity['manager'], 'onDestroy')
|
|
100
|
+
await activity.onDestroy()
|
|
101
|
+
assert.isTrue(spy.calledOnce)
|
|
102
|
+
})
|
|
103
|
+
|
|
82
104
|
it('sets the default state', async () => {
|
|
83
105
|
assert.equal(activity.state, ActivityState.Initialized)
|
|
84
106
|
})
|
|
@@ -86,6 +108,22 @@ describe('Events', () => {
|
|
|
86
108
|
it('sets the default resultCode', async () => {
|
|
87
109
|
assert.equal(activity.resultCode, IntentResult.RESULT_CANCELED)
|
|
88
110
|
})
|
|
111
|
+
|
|
112
|
+
it('onNewIntent can be called', async () => {
|
|
113
|
+
assert.doesNotThrow(async () => {
|
|
114
|
+
await activity.onNewIntent({ action: 'test' })
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('onFirstRender can be called', () => {
|
|
119
|
+
assert.doesNotThrow(() => {
|
|
120
|
+
activity.onFirstRender()
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('render returns nothing by default', () => {
|
|
125
|
+
assert.strictEqual(activity.render(), nothing)
|
|
126
|
+
})
|
|
89
127
|
})
|
|
90
128
|
|
|
91
129
|
describe('setResult()', () => {
|
|
@@ -95,6 +133,7 @@ describe('setResult()', () => {
|
|
|
95
133
|
beforeEach(async () => {
|
|
96
134
|
const renderRoot = await basicFixture()
|
|
97
135
|
application = new TestApplication(renderRoot)
|
|
136
|
+
// application.onStart() creates an activity instance via the manager
|
|
98
137
|
await application.onStart()
|
|
99
138
|
activity = application.manager.findActiveActivity(TestActivity.action) as Activity
|
|
100
139
|
})
|
|
@@ -107,6 +146,21 @@ describe('setResult()', () => {
|
|
|
107
146
|
})
|
|
108
147
|
})
|
|
109
148
|
|
|
149
|
+
describe('getResult()', () => {
|
|
150
|
+
let application: Application
|
|
151
|
+
let activity: Activity
|
|
152
|
+
|
|
153
|
+
beforeEach(async () => {
|
|
154
|
+
const renderRoot = await basicFixture()
|
|
155
|
+
application = new TestApplication(renderRoot)
|
|
156
|
+
activity = new TestActivity(application) // Test with a fresh activity not from manager
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('returns undefined by default', () => {
|
|
160
|
+
assert.isUndefined(activity.getResult())
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
110
164
|
describe('getApplication()', () => {
|
|
111
165
|
let application: Application
|
|
112
166
|
let activity: Activity
|
|
@@ -114,6 +168,7 @@ describe('getApplication()', () => {
|
|
|
114
168
|
beforeEach(async () => {
|
|
115
169
|
const renderRoot = await basicFixture()
|
|
116
170
|
application = new TestApplication(renderRoot)
|
|
171
|
+
// application.onStart() creates an activity instance via the manager
|
|
117
172
|
await application.onStart()
|
|
118
173
|
activity = application.manager.findActiveActivity(TestActivity.action) as Activity
|
|
119
174
|
})
|
|
@@ -130,6 +185,7 @@ describe('getActivity()', () => {
|
|
|
130
185
|
beforeEach(async () => {
|
|
131
186
|
const renderRoot = await basicFixture()
|
|
132
187
|
application = new TestApplication(renderRoot)
|
|
188
|
+
// application.onStart() creates an activity instance via the manager
|
|
133
189
|
await application.onStart()
|
|
134
190
|
activity = application.manager.findActiveActivity(TestActivity.action) as Activity
|
|
135
191
|
})
|
|
@@ -146,6 +202,7 @@ describe('hasRequestCode()', () => {
|
|
|
146
202
|
beforeEach(async () => {
|
|
147
203
|
const renderRoot = await basicFixture()
|
|
148
204
|
application = new TestApplication(renderRoot)
|
|
205
|
+
// application.onStart() creates an activity instance via the manager
|
|
149
206
|
await application.onStart()
|
|
150
207
|
activity = application.manager.findActiveActivity(TestActivity.action) as Activity
|
|
151
208
|
})
|
|
@@ -155,7 +212,7 @@ describe('hasRequestCode()', () => {
|
|
|
155
212
|
assert.isTrue(activity.hasRequestCode(requestCode))
|
|
156
213
|
})
|
|
157
214
|
|
|
158
|
-
it('returns
|
|
215
|
+
it('returns false when request code is not pending', async () => {
|
|
159
216
|
await activity.startActivityForResult({ action: TestActivity.action })
|
|
160
217
|
assert.isFalse(activity.hasRequestCode(1))
|
|
161
218
|
})
|
|
@@ -168,6 +225,7 @@ describe('onActivityResult()', () => {
|
|
|
168
225
|
beforeEach(async () => {
|
|
169
226
|
const renderRoot = await basicFixture()
|
|
170
227
|
application = new TestApplication(renderRoot)
|
|
228
|
+
// application.onStart() creates an activity instance via the manager
|
|
171
229
|
await application.onStart()
|
|
172
230
|
activity = application.manager.findActiveActivity(TestActivity.action) as Activity
|
|
173
231
|
})
|
|
@@ -177,4 +235,179 @@ describe('onActivityResult()', () => {
|
|
|
177
235
|
await activity.onActivityResult(2, IntentResult.RESULT_OK, { action: 'test' })
|
|
178
236
|
})
|
|
179
237
|
})
|
|
238
|
+
|
|
239
|
+
it('removes request code if present', async () => {
|
|
240
|
+
const requestCode = await activity.startActivityForResult({ action: TestActivity.action })
|
|
241
|
+
assert.isTrue(activity.hasRequestCode(requestCode))
|
|
242
|
+
await activity.onActivityResult(requestCode, IntentResult.RESULT_OK, { action: 'test' })
|
|
243
|
+
assert.isFalse(activity.hasRequestCode(requestCode))
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('forwards to fragment if fragment has request code', async () => {
|
|
247
|
+
const fragment = new TestFragment()
|
|
248
|
+
const onActivityResultStub = sinon.spy(fragment, 'onActivityResult')
|
|
249
|
+
sinon.stub(fragment, 'hasRequestCode').returns(true)
|
|
250
|
+
sinon.stub(activity['manager'], 'findByRequestCode').returns(fragment as unknown as Fragment)
|
|
251
|
+
const requestCode = 123
|
|
252
|
+
await activity.onActivityResult(requestCode, IntentResult.RESULT_OK, { action: 'test' })
|
|
253
|
+
assert.isTrue(onActivityResultStub.calledOnceWith(requestCode, IntentResult.RESULT_OK, { action: 'test' }))
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('logs info if not handled by fragment and is base Activity', async () => {
|
|
257
|
+
sinon.stub(activity['manager'], 'findByRequestCode').returns(null)
|
|
258
|
+
const consoleSpy = sinon.spy(console, 'info')
|
|
259
|
+
const requestCode = 123
|
|
260
|
+
// Ensure the activity instance is exactly Activity, not a subclass that might override onActivityResult
|
|
261
|
+
Object.setPrototypeOf(activity, Activity.prototype)
|
|
262
|
+
|
|
263
|
+
await activity.onActivityResult(requestCode, IntentResult.RESULT_OK, { action: 'test-intent' })
|
|
264
|
+
assert.isTrue(
|
|
265
|
+
consoleSpy.calledWith(
|
|
266
|
+
`Activity#onActivityResult not implemented. Request code: ${requestCode}, result code: ${IntentResult.RESULT_OK}`,
|
|
267
|
+
{ action: 'test-intent' }
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
consoleSpy.restore()
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
describe('Activity Actions', () => {
|
|
275
|
+
let application: Application
|
|
276
|
+
let activity: Activity
|
|
277
|
+
|
|
278
|
+
beforeEach(async () => {
|
|
279
|
+
const renderRoot = await basicFixture()
|
|
280
|
+
application = new TestApplication(renderRoot)
|
|
281
|
+
// For these tests, we often need a fresh activity instance not necessarily from the manager's stack
|
|
282
|
+
// to avoid side effects from application.onStart() unless specifically testing manager interactions.
|
|
283
|
+
activity = new TestActivity(application)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('startActivity calls application manager startActivity', async () => {
|
|
287
|
+
const intent = { action: TestActivity2.action }
|
|
288
|
+
const spy = sinon.spy(application.manager, 'startActivity')
|
|
289
|
+
await application.onStart() // Ensure the manager is initialized
|
|
290
|
+
await activity.startActivity(intent)
|
|
291
|
+
assert.isTrue(spy.calledOnceWith(intent))
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it('startActivityForResult calls application manager startActivityForResult and stores request code', async () => {
|
|
295
|
+
const intent = { action: TestActivity2.action }
|
|
296
|
+
const managerSpy = sinon.spy(application.manager, 'startActivityForResult')
|
|
297
|
+
const createCodeSpy = sinon.stub(application.manager, 'createRequestCode').returns(999)
|
|
298
|
+
await application.onStart() // Ensure the manager is initialized
|
|
299
|
+
const requestCode = await activity.startActivityForResult(intent)
|
|
300
|
+
|
|
301
|
+
assert.equal(requestCode, 999)
|
|
302
|
+
assert.isTrue(managerSpy.calledOnceWith(intent, 999))
|
|
303
|
+
assert.isTrue(activity.hasRequestCode(999))
|
|
304
|
+
|
|
305
|
+
createCodeSpy.restore()
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('finish calls application manager finishActivity', async () => {
|
|
309
|
+
const spy = sinon.spy(application.manager, 'finishActivity')
|
|
310
|
+
await activity.finish()
|
|
311
|
+
assert.isTrue(spy.calledOnceWith(activity))
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('requestUpdate calls parent application requestUpdate and manager updateActiveFragments', () => {
|
|
315
|
+
const appSpy = sinon.spy(application, 'requestUpdate')
|
|
316
|
+
const managerSpy = sinon.spy(activity['manager'], 'updateActiveFragments')
|
|
317
|
+
const opts = { app: false, activity: true, fragment: false }
|
|
318
|
+
activity.requestUpdate(opts)
|
|
319
|
+
assert.isTrue(appSpy.calledOnceWith(opts))
|
|
320
|
+
assert.isTrue(managerSpy.calledOnce)
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('requestUpdate defaults to updating activity fragments', () => {
|
|
324
|
+
const managerSpy = sinon.spy(activity['manager'], 'updateActiveFragments')
|
|
325
|
+
activity.requestUpdate() // No opts, so activity should be true by default
|
|
326
|
+
assert.isTrue(managerSpy.calledOnce)
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('requestUpdate respects activity: false in opts', () => {
|
|
330
|
+
const managerSpy = sinon.spy(activity['manager'], 'updateActiveFragments')
|
|
331
|
+
activity.requestUpdate({ activity: false })
|
|
332
|
+
assert.isFalse(managerSpy.called)
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
describe('Fragment Management', () => {
|
|
337
|
+
let application: Application
|
|
338
|
+
let activity: Activity
|
|
339
|
+
|
|
340
|
+
beforeEach(async () => {
|
|
341
|
+
const renderRoot = await basicFixture()
|
|
342
|
+
application = new TestApplication(renderRoot)
|
|
343
|
+
activity = new TestActivity(application)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('addFragment calls manager.attachFragment', async () => {
|
|
347
|
+
const spy = sinon.spy(activity['manager'], 'attachFragment')
|
|
348
|
+
const fragment = new TestFragment()
|
|
349
|
+
const data = { info: 'test' }
|
|
350
|
+
await activity.addFragment('testKey', fragment, data)
|
|
351
|
+
assert.isTrue(spy.calledOnceWith('testKey', fragment, activity, data))
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('showFragment calls manager.showFragment', async () => {
|
|
355
|
+
const spy = sinon.spy(activity['manager'], 'showFragment')
|
|
356
|
+
activity.addFragment('testKey', new TestFragment()) // Ensure fragment exists
|
|
357
|
+
const rootEl = document.createElement('div')
|
|
358
|
+
await activity.showFragment('testKey', rootEl)
|
|
359
|
+
assert.isTrue(spy.calledOnceWith('testKey', rootEl))
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('hideFragment calls manager.hideFragment if fragment exists', async () => {
|
|
363
|
+
const fragment = new TestFragment()
|
|
364
|
+
sinon.stub(activity['manager'], 'findFragment').returns(fragment)
|
|
365
|
+
const spy = sinon.spy(activity['manager'], 'hideFragment')
|
|
366
|
+
await activity.hideFragment('testKey')
|
|
367
|
+
assert.isTrue(spy.calledOnceWith(fragment))
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('hideFragment does not call manager.hideFragment if fragment does not exist', async () => {
|
|
371
|
+
sinon.stub(activity['manager'], 'findFragment').returns(undefined)
|
|
372
|
+
const spy = sinon.spy(activity['manager'], 'hideFragment')
|
|
373
|
+
await activity.hideFragment('testKey')
|
|
374
|
+
assert.isFalse(spy.called)
|
|
375
|
+
})
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
describe('handleIntentEvent', () => {
|
|
379
|
+
let activity: Activity
|
|
380
|
+
|
|
381
|
+
beforeEach(async () => {
|
|
382
|
+
const renderRoot = await basicFixture()
|
|
383
|
+
const application = new TestApplication(renderRoot)
|
|
384
|
+
await application.onStart() // Ensure the manager is initialized
|
|
385
|
+
activity = new TestActivity(application)
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
it('handles startActivityForResult event', async () => {
|
|
389
|
+
const startActivityForResultSpy = sinon.spy(activity, 'startActivityForResult')
|
|
390
|
+
const detail = { intent: { action: TestActivity2.action }, onResult: () => {} }
|
|
391
|
+
const event = new CustomEvent(EventTypes.Intent.startActivityForResult, { detail })
|
|
392
|
+
await activity.handleIntentEvent(event)
|
|
393
|
+
assert.isTrue(startActivityForResultSpy.calledOnceWith(detail.intent))
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
it('handles startActivity event', async () => {
|
|
397
|
+
const startActivitySpy = sinon.spy(activity, 'startActivity')
|
|
398
|
+
const detail = { intent: { action: TestActivity2.action } }
|
|
399
|
+
const event = new CustomEvent(EventTypes.Intent.startActivity, { detail })
|
|
400
|
+
await activity.handleIntentEvent(event)
|
|
401
|
+
assert.isTrue(startActivitySpy.calledOnceWith(detail.intent))
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('throws error for unrecognized event type', async () => {
|
|
405
|
+
const event = new CustomEvent('unknown-event', { detail: {} as unknown as ActivityDetail })
|
|
406
|
+
try {
|
|
407
|
+
await activity.handleIntentEvent(event)
|
|
408
|
+
assert.fail('Should have thrown an error')
|
|
409
|
+
} catch (e) {
|
|
410
|
+
assert.equal((e as Error).message, `Unrecognized intent event: unknown-event`)
|
|
411
|
+
}
|
|
412
|
+
})
|
|
180
413
|
})
|