@symbiote-native/sensors 0.1.0
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/LICENSE +21 -0
- package/README.md +138 -0
- package/build/angular/index.d.ts +16 -0
- package/build/angular/index.js +12 -0
- package/build/angular/services/accelerometer.service/index.d.ts +6 -0
- package/build/angular/services/accelerometer.service/index.js +81 -0
- package/build/angular/services/barometer.service/index.d.ts +6 -0
- package/build/angular/services/barometer.service/index.js +81 -0
- package/build/angular/services/device-motion.service/index.d.ts +6 -0
- package/build/angular/services/device-motion.service/index.js +81 -0
- package/build/angular/services/gyroscope.service/index.d.ts +6 -0
- package/build/angular/services/gyroscope.service/index.js +81 -0
- package/build/angular/services/light-sensor.service/index.d.ts +6 -0
- package/build/angular/services/light-sensor.service/index.js +81 -0
- package/build/angular/services/magnetometer-uncalibrated.service/index.d.ts +6 -0
- package/build/angular/services/magnetometer-uncalibrated.service/index.js +81 -0
- package/build/angular/services/magnetometer.service/index.d.ts +6 -0
- package/build/angular/services/magnetometer.service/index.js +81 -0
- package/build/angular/services/pedometer.service/index.d.ts +6 -0
- package/build/angular/services/pedometer.service/index.js +76 -0
- package/build/core/accelerometer.d.ts +10 -0
- package/build/core/accelerometer.js +6 -0
- package/build/core/barometer.d.ts +9 -0
- package/build/core/barometer.js +6 -0
- package/build/core/device-motion.d.ts +40 -0
- package/build/core/device-motion.js +21 -0
- package/build/core/device-sensor.d.ts +27 -0
- package/build/core/device-sensor.js +61 -0
- package/build/core/gyroscope.d.ts +10 -0
- package/build/core/gyroscope.js +6 -0
- package/build/core/index.d.ts +11 -0
- package/build/core/index.js +10 -0
- package/build/core/light-sensor.d.ts +8 -0
- package/build/core/light-sensor.js +6 -0
- package/build/core/magnetometer-uncalibrated.d.ts +10 -0
- package/build/core/magnetometer-uncalibrated.js +6 -0
- package/build/core/magnetometer.d.ts +10 -0
- package/build/core/magnetometer.js +6 -0
- package/build/core/native/exponent-accelerometer.d.ts +3 -0
- package/build/core/native/exponent-accelerometer.js +3 -0
- package/build/core/native/exponent-barometer.d.ts +3 -0
- package/build/core/native/exponent-barometer.js +3 -0
- package/build/core/native/exponent-device-motion.d.ts +7 -0
- package/build/core/native/exponent-device-motion.js +3 -0
- package/build/core/native/exponent-gyroscope.d.ts +3 -0
- package/build/core/native/exponent-gyroscope.js +3 -0
- package/build/core/native/exponent-light-sensor/index.android.d.ts +3 -0
- package/build/core/native/exponent-light-sensor/index.android.js +3 -0
- package/build/core/native/exponent-light-sensor/index.d.ts +1 -0
- package/build/core/native/exponent-light-sensor/index.ios.d.ts +3 -0
- package/build/core/native/exponent-light-sensor/index.ios.js +6 -0
- package/build/core/native/exponent-light-sensor/index.js +5 -0
- package/build/core/native/exponent-magnetometer-uncalibrated.d.ts +3 -0
- package/build/core/native/exponent-magnetometer-uncalibrated.js +3 -0
- package/build/core/native/exponent-magnetometer.d.ts +3 -0
- package/build/core/native/exponent-magnetometer.js +3 -0
- package/build/core/native/exponent-pedometer.d.ts +10 -0
- package/build/core/native/exponent-pedometer.js +3 -0
- package/build/core/pedometer.d.ts +10 -0
- package/build/core/pedometer.js +44 -0
- package/build/react/hooks/use-accelerometer/index.d.ts +2 -0
- package/build/react/hooks/use-accelerometer/index.js +17 -0
- package/build/react/hooks/use-barometer/index.d.ts +2 -0
- package/build/react/hooks/use-barometer/index.js +17 -0
- package/build/react/hooks/use-device-motion/index.d.ts +2 -0
- package/build/react/hooks/use-device-motion/index.js +17 -0
- package/build/react/hooks/use-gyroscope/index.d.ts +2 -0
- package/build/react/hooks/use-gyroscope/index.js +17 -0
- package/build/react/hooks/use-light-sensor/index.d.ts +2 -0
- package/build/react/hooks/use-light-sensor/index.js +17 -0
- package/build/react/hooks/use-magnetometer/index.d.ts +2 -0
- package/build/react/hooks/use-magnetometer/index.js +17 -0
- package/build/react/hooks/use-magnetometer-uncalibrated/index.d.ts +2 -0
- package/build/react/hooks/use-magnetometer-uncalibrated/index.js +17 -0
- package/build/react/hooks/use-pedometer/index.d.ts +2 -0
- package/build/react/hooks/use-pedometer/index.js +14 -0
- package/build/react/index.d.ts +16 -0
- package/build/react/index.js +14 -0
- package/build/vue/composables/use-accelerometer/index.d.ts +3 -0
- package/build/vue/composables/use-accelerometer/index.js +25 -0
- package/build/vue/composables/use-barometer/index.d.ts +3 -0
- package/build/vue/composables/use-barometer/index.js +25 -0
- package/build/vue/composables/use-device-motion/index.d.ts +3 -0
- package/build/vue/composables/use-device-motion/index.js +25 -0
- package/build/vue/composables/use-gyroscope/index.d.ts +3 -0
- package/build/vue/composables/use-gyroscope/index.js +25 -0
- package/build/vue/composables/use-light-sensor/index.d.ts +3 -0
- package/build/vue/composables/use-light-sensor/index.js +25 -0
- package/build/vue/composables/use-magnetometer/index.d.ts +3 -0
- package/build/vue/composables/use-magnetometer/index.js +25 -0
- package/build/vue/composables/use-magnetometer-uncalibrated/index.d.ts +3 -0
- package/build/vue/composables/use-magnetometer-uncalibrated/index.js +25 -0
- package/build/vue/composables/use-pedometer/index.d.ts +3 -0
- package/build/vue/composables/use-pedometer/index.js +20 -0
- package/build/vue/index.d.ts +16 -0
- package/build/vue/index.js +14 -0
- package/build-ngc/angular/index.d.ts +16 -0
- package/build-ngc/angular/index.js +13 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/services/accelerometer.service/index.d.ts +9 -0
- package/build-ngc/angular/services/accelerometer.service/index.js +40 -0
- package/build-ngc/angular/services/accelerometer.service/index.js.map +1 -0
- package/build-ngc/angular/services/barometer.service/index.d.ts +9 -0
- package/build-ngc/angular/services/barometer.service/index.js +40 -0
- package/build-ngc/angular/services/barometer.service/index.js.map +1 -0
- package/build-ngc/angular/services/device-motion.service/index.d.ts +9 -0
- package/build-ngc/angular/services/device-motion.service/index.js +40 -0
- package/build-ngc/angular/services/device-motion.service/index.js.map +1 -0
- package/build-ngc/angular/services/gyroscope.service/index.d.ts +9 -0
- package/build-ngc/angular/services/gyroscope.service/index.js +40 -0
- package/build-ngc/angular/services/gyroscope.service/index.js.map +1 -0
- package/build-ngc/angular/services/light-sensor.service/index.d.ts +9 -0
- package/build-ngc/angular/services/light-sensor.service/index.js +40 -0
- package/build-ngc/angular/services/light-sensor.service/index.js.map +1 -0
- package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.d.ts +9 -0
- package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.js +40 -0
- package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.js.map +1 -0
- package/build-ngc/angular/services/magnetometer.service/index.d.ts +9 -0
- package/build-ngc/angular/services/magnetometer.service/index.js +40 -0
- package/build-ngc/angular/services/magnetometer.service/index.js.map +1 -0
- package/build-ngc/angular/services/pedometer.service/index.d.ts +9 -0
- package/build-ngc/angular/services/pedometer.service/index.js +35 -0
- package/build-ngc/angular/services/pedometer.service/index.js.map +1 -0
- package/build-ngc/core/accelerometer.d.ts +10 -0
- package/build-ngc/core/accelerometer.js +7 -0
- package/build-ngc/core/accelerometer.js.map +1 -0
- package/build-ngc/core/barometer.d.ts +9 -0
- package/build-ngc/core/barometer.js +7 -0
- package/build-ngc/core/barometer.js.map +1 -0
- package/build-ngc/core/device-motion.d.ts +40 -0
- package/build-ngc/core/device-motion.js +22 -0
- package/build-ngc/core/device-motion.js.map +1 -0
- package/build-ngc/core/device-sensor.d.ts +27 -0
- package/build-ngc/core/device-sensor.js +62 -0
- package/build-ngc/core/device-sensor.js.map +1 -0
- package/build-ngc/core/gyroscope.d.ts +10 -0
- package/build-ngc/core/gyroscope.js +7 -0
- package/build-ngc/core/gyroscope.js.map +1 -0
- package/build-ngc/core/index.d.ts +11 -0
- package/build-ngc/core/index.js +11 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/light-sensor.d.ts +8 -0
- package/build-ngc/core/light-sensor.js +7 -0
- package/build-ngc/core/light-sensor.js.map +1 -0
- package/build-ngc/core/magnetometer-uncalibrated.d.ts +10 -0
- package/build-ngc/core/magnetometer-uncalibrated.js +7 -0
- package/build-ngc/core/magnetometer-uncalibrated.js.map +1 -0
- package/build-ngc/core/magnetometer.d.ts +10 -0
- package/build-ngc/core/magnetometer.js +7 -0
- package/build-ngc/core/magnetometer.js.map +1 -0
- package/build-ngc/core/native/exponent-accelerometer.d.ts +3 -0
- package/build-ngc/core/native/exponent-accelerometer.js +4 -0
- package/build-ngc/core/native/exponent-accelerometer.js.map +1 -0
- package/build-ngc/core/native/exponent-barometer.d.ts +3 -0
- package/build-ngc/core/native/exponent-barometer.js +4 -0
- package/build-ngc/core/native/exponent-barometer.js.map +1 -0
- package/build-ngc/core/native/exponent-device-motion.d.ts +7 -0
- package/build-ngc/core/native/exponent-device-motion.js +4 -0
- package/build-ngc/core/native/exponent-device-motion.js.map +1 -0
- package/build-ngc/core/native/exponent-gyroscope.d.ts +3 -0
- package/build-ngc/core/native/exponent-gyroscope.js +4 -0
- package/build-ngc/core/native/exponent-gyroscope.js.map +1 -0
- package/build-ngc/core/native/exponent-light-sensor/index.android.d.ts +3 -0
- package/build-ngc/core/native/exponent-light-sensor/index.android.js +4 -0
- package/build-ngc/core/native/exponent-light-sensor/index.android.js.map +1 -0
- package/build-ngc/core/native/exponent-light-sensor/index.d.ts +1 -0
- package/build-ngc/core/native/exponent-light-sensor/index.ios.d.ts +3 -0
- package/build-ngc/core/native/exponent-light-sensor/index.ios.js +7 -0
- package/build-ngc/core/native/exponent-light-sensor/index.ios.js.map +1 -0
- package/build-ngc/core/native/exponent-light-sensor/index.js +6 -0
- package/build-ngc/core/native/exponent-light-sensor/index.js.map +1 -0
- package/build-ngc/core/native/exponent-magnetometer-uncalibrated.d.ts +3 -0
- package/build-ngc/core/native/exponent-magnetometer-uncalibrated.js +4 -0
- package/build-ngc/core/native/exponent-magnetometer-uncalibrated.js.map +1 -0
- package/build-ngc/core/native/exponent-magnetometer.d.ts +3 -0
- package/build-ngc/core/native/exponent-magnetometer.js +4 -0
- package/build-ngc/core/native/exponent-magnetometer.js.map +1 -0
- package/build-ngc/core/native/exponent-pedometer.d.ts +10 -0
- package/build-ngc/core/native/exponent-pedometer.js +4 -0
- package/build-ngc/core/native/exponent-pedometer.js.map +1 -0
- package/build-ngc/core/pedometer.d.ts +10 -0
- package/build-ngc/core/pedometer.js +45 -0
- package/build-ngc/core/pedometer.js.map +1 -0
- package/package.json +106 -0
- package/src/angular/index.ts +26 -0
- package/src/angular/services/accelerometer.service/accelerometer.service.test.ts +118 -0
- package/src/angular/services/accelerometer.service/index.ts +39 -0
- package/src/angular/services/barometer.service/barometer.service.test.ts +122 -0
- package/src/angular/services/barometer.service/index.ts +39 -0
- package/src/angular/services/device-motion.service/device-motion.service.test.ts +125 -0
- package/src/angular/services/device-motion.service/index.ts +39 -0
- package/src/angular/services/gyroscope.service/gyroscope.service.test.ts +118 -0
- package/src/angular/services/gyroscope.service/index.ts +39 -0
- package/src/angular/services/light-sensor.service/index.ts +39 -0
- package/src/angular/services/light-sensor.service/light-sensor.service.test.ts +118 -0
- package/src/angular/services/magnetometer-uncalibrated.service/index.ts +39 -0
- package/src/angular/services/magnetometer-uncalibrated.service/magnetometer-uncalibrated.service.test.ts +123 -0
- package/src/angular/services/magnetometer.service/index.ts +39 -0
- package/src/angular/services/magnetometer.service/magnetometer.service.test.ts +118 -0
- package/src/angular/services/pedometer.service/index.ts +34 -0
- package/src/angular/services/pedometer.service/pedometer.service.test.ts +86 -0
- package/src/core/accelerometer.test.ts +49 -0
- package/src/core/accelerometer.ts +19 -0
- package/src/core/barometer.test.ts +46 -0
- package/src/core/barometer.ts +15 -0
- package/src/core/device-motion.test.ts +60 -0
- package/src/core/device-motion.ts +41 -0
- package/src/core/device-sensor.test.ts +76 -0
- package/src/core/device-sensor.ts +95 -0
- package/src/core/gyroscope.test.ts +46 -0
- package/src/core/gyroscope.ts +16 -0
- package/src/core/index.ts +37 -0
- package/src/core/light-sensor.test.ts +49 -0
- package/src/core/light-sensor.ts +18 -0
- package/src/core/magnetometer-uncalibrated.test.ts +49 -0
- package/src/core/magnetometer-uncalibrated.ts +20 -0
- package/src/core/magnetometer.test.ts +49 -0
- package/src/core/magnetometer.ts +19 -0
- package/src/core/native/exponent-accelerometer.ts +9 -0
- package/src/core/native/exponent-barometer.ts +9 -0
- package/src/core/native/exponent-device-motion.ts +15 -0
- package/src/core/native/exponent-gyroscope.ts +9 -0
- package/src/core/native/exponent-light-sensor/index.android.ts +9 -0
- package/src/core/native/exponent-light-sensor/index.ios.ts +12 -0
- package/src/core/native/exponent-light-sensor/index.ts +5 -0
- package/src/core/native/exponent-magnetometer-uncalibrated.ts +9 -0
- package/src/core/native/exponent-magnetometer.ts +9 -0
- package/src/core/native/exponent-pedometer.ts +17 -0
- package/src/core/pedometer.test.ts +118 -0
- package/src/core/pedometer.ts +62 -0
- package/src/react/hooks/use-accelerometer/index.ts +21 -0
- package/src/react/hooks/use-accelerometer/use-accelerometer.test.tsx +81 -0
- package/src/react/hooks/use-barometer/index.ts +21 -0
- package/src/react/hooks/use-barometer/use-barometer.test.tsx +83 -0
- package/src/react/hooks/use-device-motion/index.ts +21 -0
- package/src/react/hooks/use-device-motion/use-device-motion.test.tsx +88 -0
- package/src/react/hooks/use-gyroscope/index.ts +21 -0
- package/src/react/hooks/use-gyroscope/use-gyroscope.test.tsx +79 -0
- package/src/react/hooks/use-light-sensor/index.ts +21 -0
- package/src/react/hooks/use-light-sensor/use-light-sensor.test.tsx +79 -0
- package/src/react/hooks/use-magnetometer/index.ts +21 -0
- package/src/react/hooks/use-magnetometer/use-magnetometer.test.tsx +81 -0
- package/src/react/hooks/use-magnetometer-uncalibrated/index.ts +23 -0
- package/src/react/hooks/use-magnetometer-uncalibrated/use-magnetometer-uncalibrated.test.tsx +88 -0
- package/src/react/hooks/use-pedometer/index.ts +17 -0
- package/src/react/hooks/use-pedometer/use-pedometer.test.tsx +69 -0
- package/src/react/index.ts +29 -0
- package/src/vue/composables/use-accelerometer/index.ts +34 -0
- package/src/vue/composables/use-accelerometer/use-accelerometer.test.ts +96 -0
- package/src/vue/composables/use-barometer/index.ts +30 -0
- package/src/vue/composables/use-barometer/use-barometer.test.ts +100 -0
- package/src/vue/composables/use-device-motion/index.ts +30 -0
- package/src/vue/composables/use-device-motion/use-device-motion.test.ts +104 -0
- package/src/vue/composables/use-gyroscope/index.ts +30 -0
- package/src/vue/composables/use-gyroscope/use-gyroscope.test.ts +96 -0
- package/src/vue/composables/use-light-sensor/index.ts +30 -0
- package/src/vue/composables/use-light-sensor/use-light-sensor.test.ts +96 -0
- package/src/vue/composables/use-magnetometer/index.ts +30 -0
- package/src/vue/composables/use-magnetometer/use-magnetometer.test.ts +96 -0
- package/src/vue/composables/use-magnetometer-uncalibrated/index.ts +36 -0
- package/src/vue/composables/use-magnetometer-uncalibrated/use-magnetometer-uncalibrated.test.ts +103 -0
- package/src/vue/composables/use-pedometer/index.ts +25 -0
- package/src/vue/composables/use-pedometer/use-pedometer.test.ts +77 -0
- package/src/vue/index.ts +29 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Co-located Vue-driven test (ADR 0025) for useBarometer. Mocks the whole core module
|
|
2
|
+
// (never expo-modules-core internals) since this exercises composable mount/unmount lifecycle
|
|
3
|
+
// timing, not any native view — there is none here, so no ViewConfig fixture is needed.
|
|
4
|
+
|
|
5
|
+
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { mount, unmount } from '@symbiote-native/vue';
|
|
8
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
+
import type { IBarometerMeasurement } from '../../../core';
|
|
10
|
+
import { useBarometer } from './index';
|
|
11
|
+
|
|
12
|
+
const ROOT_TAG = 9822;
|
|
13
|
+
|
|
14
|
+
type IListener = (measurement: IBarometerMeasurement) => void;
|
|
15
|
+
|
|
16
|
+
let registeredListener: IListener | undefined;
|
|
17
|
+
const removeMock = vi.fn();
|
|
18
|
+
const addListenerMock = vi.fn((listener: IListener) => {
|
|
19
|
+
registeredListener = listener;
|
|
20
|
+
return { remove: removeMock };
|
|
21
|
+
});
|
|
22
|
+
const setUpdateIntervalMock = vi.fn();
|
|
23
|
+
|
|
24
|
+
vi.mock('../../../core', () => ({
|
|
25
|
+
Barometer: {
|
|
26
|
+
addListener: (listener: IListener) => addListenerMock(listener),
|
|
27
|
+
removeAllListeners: vi.fn(),
|
|
28
|
+
setUpdateInterval: (intervalMs: number) => setUpdateIntervalMock(intervalMs),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const fabric = installFabric();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
fabric.reset();
|
|
36
|
+
registeredListener = undefined;
|
|
37
|
+
addListenerMock.mockClear();
|
|
38
|
+
removeMock.mockClear();
|
|
39
|
+
setUpdateIntervalMock.mockClear();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
43
|
+
|
|
44
|
+
function mountBarometer(updateIntervalMs?: number): Ref<IBarometerMeasurement | null> {
|
|
45
|
+
let measurement: Ref<IBarometerMeasurement | null> | undefined;
|
|
46
|
+
mount(
|
|
47
|
+
ROOT_TAG,
|
|
48
|
+
defineComponent({
|
|
49
|
+
setup: () => {
|
|
50
|
+
measurement = useBarometer(updateIntervalMs);
|
|
51
|
+
return () => h('symbiote-text', {}, 'sensor');
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (measurement === undefined) {
|
|
56
|
+
throw new Error('setup() did not run');
|
|
57
|
+
}
|
|
58
|
+
return measurement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('useBarometer (Vue)', () => {
|
|
62
|
+
it('starts null before any measurement arrives', () => {
|
|
63
|
+
const measurement = mountBarometer();
|
|
64
|
+
|
|
65
|
+
expect(measurement.value).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('updates the ref when the native listener fires', () => {
|
|
69
|
+
const measurement = mountBarometer();
|
|
70
|
+
const reading: IBarometerMeasurement = {
|
|
71
|
+
pressure: 1013.25,
|
|
72
|
+
relativeAltitude: 12.3,
|
|
73
|
+
timestamp: 123,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
registeredListener?.(reading);
|
|
77
|
+
|
|
78
|
+
expect(measurement.value).toEqual(reading);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('removes the subscription on unmount', () => {
|
|
82
|
+
mountBarometer();
|
|
83
|
+
unmount(ROOT_TAG);
|
|
84
|
+
|
|
85
|
+
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('sets the update interval once at subscribe time when provided', () => {
|
|
89
|
+
mountBarometer(50);
|
|
90
|
+
|
|
91
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledWith(50);
|
|
92
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledTimes(1);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('does not touch the update interval when omitted', () => {
|
|
96
|
+
mountBarometer();
|
|
97
|
+
|
|
98
|
+
expect(setUpdateIntervalMock).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic DeviceMotion singleton (core/) — mirrors
|
|
2
|
+
// the lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of use-color-scheme.ts's subscription handle. Unlike
|
|
4
|
+
// use-hide-animation.ts (which takes a config getter because its consumer's config changes
|
|
5
|
+
// across reactive updates), this subscribes exactly once at mount and never needs to react to
|
|
6
|
+
// a later change of updateIntervalMs, so a plain numeric param is enough.
|
|
7
|
+
|
|
8
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
9
|
+
import { DeviceMotion, type EventSubscription, type IDeviceMotionMeasurement } from '../../../core';
|
|
10
|
+
|
|
11
|
+
export function useDeviceMotion(updateIntervalMs?: number): Ref<IDeviceMotionMeasurement | null> {
|
|
12
|
+
// A plain ref: the value is a POJO measurement, not an engine node, so no shallowRef needed.
|
|
13
|
+
const measurement = ref<IDeviceMotionMeasurement | null>(null);
|
|
14
|
+
let subscription: EventSubscription | undefined;
|
|
15
|
+
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
if (updateIntervalMs !== undefined) {
|
|
18
|
+
DeviceMotion.setUpdateInterval(updateIntervalMs);
|
|
19
|
+
}
|
|
20
|
+
subscription = DeviceMotion.addListener(next => {
|
|
21
|
+
measurement.value = next;
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => {
|
|
26
|
+
subscription?.remove();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return measurement;
|
|
30
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Co-located Vue-driven test (ADR 0025) for useDeviceMotion. Mocks the whole core module
|
|
2
|
+
// (never expo-modules-core internals) since this exercises composable mount/unmount lifecycle
|
|
3
|
+
// timing, not any native view — there is none here, so no ViewConfig fixture is needed.
|
|
4
|
+
|
|
5
|
+
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { mount, unmount } from '@symbiote-native/vue';
|
|
8
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
+
import type { IDeviceMotionMeasurement } from '../../../core';
|
|
10
|
+
import { useDeviceMotion } from './index';
|
|
11
|
+
|
|
12
|
+
const ROOT_TAG = 9822;
|
|
13
|
+
|
|
14
|
+
type IListener = (measurement: IDeviceMotionMeasurement) => void;
|
|
15
|
+
|
|
16
|
+
let registeredListener: IListener | undefined;
|
|
17
|
+
const removeMock = vi.fn();
|
|
18
|
+
const addListenerMock = vi.fn((listener: IListener) => {
|
|
19
|
+
registeredListener = listener;
|
|
20
|
+
return { remove: removeMock };
|
|
21
|
+
});
|
|
22
|
+
const setUpdateIntervalMock = vi.fn();
|
|
23
|
+
|
|
24
|
+
vi.mock('../../../core', () => ({
|
|
25
|
+
DeviceMotion: {
|
|
26
|
+
addListener: (listener: IListener) => addListenerMock(listener),
|
|
27
|
+
removeAllListeners: vi.fn(),
|
|
28
|
+
setUpdateInterval: (intervalMs: number) => setUpdateIntervalMock(intervalMs),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const fabric = installFabric();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
fabric.reset();
|
|
36
|
+
registeredListener = undefined;
|
|
37
|
+
addListenerMock.mockClear();
|
|
38
|
+
removeMock.mockClear();
|
|
39
|
+
setUpdateIntervalMock.mockClear();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
43
|
+
|
|
44
|
+
function mountDeviceMotion(updateIntervalMs?: number): Ref<IDeviceMotionMeasurement | null> {
|
|
45
|
+
let measurement: Ref<IDeviceMotionMeasurement | null> | undefined;
|
|
46
|
+
mount(
|
|
47
|
+
ROOT_TAG,
|
|
48
|
+
defineComponent({
|
|
49
|
+
setup: () => {
|
|
50
|
+
measurement = useDeviceMotion(updateIntervalMs);
|
|
51
|
+
return () => h('symbiote-text', {}, 'sensor');
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (measurement === undefined) {
|
|
56
|
+
throw new Error('setup() did not run');
|
|
57
|
+
}
|
|
58
|
+
return measurement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const READING: IDeviceMotionMeasurement = {
|
|
62
|
+
acceleration: { x: 0.1, y: 0.2, z: 0.3, timestamp: 123 },
|
|
63
|
+
accelerationIncludingGravity: { x: 0.1, y: 0.2, z: 9.9, timestamp: 123 },
|
|
64
|
+
rotation: { alpha: 1, beta: 2, gamma: 3, timestamp: 123 },
|
|
65
|
+
rotationRate: { alpha: 0.1, beta: 0.2, gamma: 0.3, timestamp: 123 },
|
|
66
|
+
interval: 16,
|
|
67
|
+
orientation: 0, // DeviceMotionOrientation.Portrait
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
describe('useDeviceMotion (Vue)', () => {
|
|
71
|
+
it('starts null before any measurement arrives', () => {
|
|
72
|
+
const measurement = mountDeviceMotion();
|
|
73
|
+
|
|
74
|
+
expect(measurement.value).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('updates the ref when the native listener fires', () => {
|
|
78
|
+
const measurement = mountDeviceMotion();
|
|
79
|
+
|
|
80
|
+
registeredListener?.(READING);
|
|
81
|
+
|
|
82
|
+
expect(measurement.value).toEqual(READING);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('removes the subscription on unmount', () => {
|
|
86
|
+
mountDeviceMotion();
|
|
87
|
+
unmount(ROOT_TAG);
|
|
88
|
+
|
|
89
|
+
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('sets the update interval once at subscribe time when provided', () => {
|
|
93
|
+
mountDeviceMotion(50);
|
|
94
|
+
|
|
95
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledWith(50);
|
|
96
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('does not touch the update interval when omitted', () => {
|
|
100
|
+
mountDeviceMotion();
|
|
101
|
+
|
|
102
|
+
expect(setUpdateIntervalMock).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic Gyroscope singleton (core/) — mirrors
|
|
2
|
+
// the lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of use-color-scheme.ts's subscription handle. Unlike
|
|
4
|
+
// use-hide-animation.ts (which takes a config getter because its consumer's config changes
|
|
5
|
+
// across reactive updates), this subscribes exactly once at mount and never needs to react to
|
|
6
|
+
// a later change of updateIntervalMs, so a plain numeric param is enough.
|
|
7
|
+
|
|
8
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
9
|
+
import { Gyroscope, type EventSubscription, type IGyroscopeMeasurement } from '../../../core';
|
|
10
|
+
|
|
11
|
+
export function useGyroscope(updateIntervalMs?: number): Ref<IGyroscopeMeasurement | null> {
|
|
12
|
+
// A plain ref: the value is a POJO measurement, not an engine node, so no shallowRef needed.
|
|
13
|
+
const measurement = ref<IGyroscopeMeasurement | null>(null);
|
|
14
|
+
let subscription: EventSubscription | undefined;
|
|
15
|
+
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
if (updateIntervalMs !== undefined) {
|
|
18
|
+
Gyroscope.setUpdateInterval(updateIntervalMs);
|
|
19
|
+
}
|
|
20
|
+
subscription = Gyroscope.addListener(next => {
|
|
21
|
+
measurement.value = next;
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => {
|
|
26
|
+
subscription?.remove();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return measurement;
|
|
30
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Co-located Vue-driven test (ADR 0025) for useGyroscope. Mocks the whole core module
|
|
2
|
+
// (never expo-modules-core internals) since this exercises composable mount/unmount lifecycle
|
|
3
|
+
// timing, not any native view — there is none here, so no ViewConfig fixture is needed.
|
|
4
|
+
|
|
5
|
+
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { mount, unmount } from '@symbiote-native/vue';
|
|
8
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
+
import type { IGyroscopeMeasurement } from '../../../core';
|
|
10
|
+
import { useGyroscope } from './index';
|
|
11
|
+
|
|
12
|
+
const ROOT_TAG = 9822;
|
|
13
|
+
|
|
14
|
+
type IListener = (measurement: IGyroscopeMeasurement) => void;
|
|
15
|
+
|
|
16
|
+
let registeredListener: IListener | undefined;
|
|
17
|
+
const removeMock = vi.fn();
|
|
18
|
+
const addListenerMock = vi.fn((listener: IListener) => {
|
|
19
|
+
registeredListener = listener;
|
|
20
|
+
return { remove: removeMock };
|
|
21
|
+
});
|
|
22
|
+
const setUpdateIntervalMock = vi.fn();
|
|
23
|
+
|
|
24
|
+
vi.mock('../../../core', () => ({
|
|
25
|
+
Gyroscope: {
|
|
26
|
+
addListener: (listener: IListener) => addListenerMock(listener),
|
|
27
|
+
removeAllListeners: vi.fn(),
|
|
28
|
+
setUpdateInterval: (intervalMs: number) => setUpdateIntervalMock(intervalMs),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const fabric = installFabric();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
fabric.reset();
|
|
36
|
+
registeredListener = undefined;
|
|
37
|
+
addListenerMock.mockClear();
|
|
38
|
+
removeMock.mockClear();
|
|
39
|
+
setUpdateIntervalMock.mockClear();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
43
|
+
|
|
44
|
+
function mountGyroscope(updateIntervalMs?: number): Ref<IGyroscopeMeasurement | null> {
|
|
45
|
+
let measurement: Ref<IGyroscopeMeasurement | null> | undefined;
|
|
46
|
+
mount(
|
|
47
|
+
ROOT_TAG,
|
|
48
|
+
defineComponent({
|
|
49
|
+
setup: () => {
|
|
50
|
+
measurement = useGyroscope(updateIntervalMs);
|
|
51
|
+
return () => h('symbiote-text', {}, 'sensor');
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (measurement === undefined) {
|
|
56
|
+
throw new Error('setup() did not run');
|
|
57
|
+
}
|
|
58
|
+
return measurement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('useGyroscope (Vue)', () => {
|
|
62
|
+
it('starts null before any measurement arrives', () => {
|
|
63
|
+
const measurement = mountGyroscope();
|
|
64
|
+
|
|
65
|
+
expect(measurement.value).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('updates the ref when the native listener fires', () => {
|
|
69
|
+
const measurement = mountGyroscope();
|
|
70
|
+
const reading: IGyroscopeMeasurement = { x: 0.1, y: 0.2, z: 0.9, timestamp: 123 };
|
|
71
|
+
|
|
72
|
+
registeredListener?.(reading);
|
|
73
|
+
|
|
74
|
+
expect(measurement.value).toEqual(reading);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('removes the subscription on unmount', () => {
|
|
78
|
+
mountGyroscope();
|
|
79
|
+
unmount(ROOT_TAG);
|
|
80
|
+
|
|
81
|
+
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('sets the update interval once at subscribe time when provided', () => {
|
|
85
|
+
mountGyroscope(50);
|
|
86
|
+
|
|
87
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledWith(50);
|
|
88
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('does not touch the update interval when omitted', () => {
|
|
92
|
+
mountGyroscope();
|
|
93
|
+
|
|
94
|
+
expect(setUpdateIntervalMock).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic LightSensor singleton (core/) — mirrors
|
|
2
|
+
// the lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of use-color-scheme.ts's subscription handle. Unlike
|
|
4
|
+
// use-hide-animation.ts (which takes a config getter because its consumer's config changes
|
|
5
|
+
// across reactive updates), this subscribes exactly once at mount and never needs to react to
|
|
6
|
+
// a later change of updateIntervalMs, so a plain numeric param is enough.
|
|
7
|
+
|
|
8
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
9
|
+
import { LightSensor, type EventSubscription, type ILightSensorMeasurement } from '../../../core';
|
|
10
|
+
|
|
11
|
+
export function useLightSensor(updateIntervalMs?: number): Ref<ILightSensorMeasurement | null> {
|
|
12
|
+
// A plain ref: the value is a POJO measurement, not an engine node, so no shallowRef needed.
|
|
13
|
+
const measurement = ref<ILightSensorMeasurement | null>(null);
|
|
14
|
+
let subscription: EventSubscription | undefined;
|
|
15
|
+
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
if (updateIntervalMs !== undefined) {
|
|
18
|
+
LightSensor.setUpdateInterval(updateIntervalMs);
|
|
19
|
+
}
|
|
20
|
+
subscription = LightSensor.addListener(next => {
|
|
21
|
+
measurement.value = next;
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => {
|
|
26
|
+
subscription?.remove();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return measurement;
|
|
30
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Co-located Vue-driven test (ADR 0025) for useLightSensor. Mocks the whole core module
|
|
2
|
+
// (never expo-modules-core internals) since this exercises composable mount/unmount lifecycle
|
|
3
|
+
// timing, not any native view — there is none here, so no ViewConfig fixture is needed.
|
|
4
|
+
|
|
5
|
+
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { mount, unmount } from '@symbiote-native/vue';
|
|
8
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
+
import type { ILightSensorMeasurement } from '../../../core';
|
|
10
|
+
import { useLightSensor } from './index';
|
|
11
|
+
|
|
12
|
+
const ROOT_TAG = 9822;
|
|
13
|
+
|
|
14
|
+
type IListener = (measurement: ILightSensorMeasurement) => void;
|
|
15
|
+
|
|
16
|
+
let registeredListener: IListener | undefined;
|
|
17
|
+
const removeMock = vi.fn();
|
|
18
|
+
const addListenerMock = vi.fn((listener: IListener) => {
|
|
19
|
+
registeredListener = listener;
|
|
20
|
+
return { remove: removeMock };
|
|
21
|
+
});
|
|
22
|
+
const setUpdateIntervalMock = vi.fn();
|
|
23
|
+
|
|
24
|
+
vi.mock('../../../core', () => ({
|
|
25
|
+
LightSensor: {
|
|
26
|
+
addListener: (listener: IListener) => addListenerMock(listener),
|
|
27
|
+
removeAllListeners: vi.fn(),
|
|
28
|
+
setUpdateInterval: (intervalMs: number) => setUpdateIntervalMock(intervalMs),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const fabric = installFabric();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
fabric.reset();
|
|
36
|
+
registeredListener = undefined;
|
|
37
|
+
addListenerMock.mockClear();
|
|
38
|
+
removeMock.mockClear();
|
|
39
|
+
setUpdateIntervalMock.mockClear();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
43
|
+
|
|
44
|
+
function mountLightSensor(updateIntervalMs?: number): Ref<ILightSensorMeasurement | null> {
|
|
45
|
+
let measurement: Ref<ILightSensorMeasurement | null> | undefined;
|
|
46
|
+
mount(
|
|
47
|
+
ROOT_TAG,
|
|
48
|
+
defineComponent({
|
|
49
|
+
setup: () => {
|
|
50
|
+
measurement = useLightSensor(updateIntervalMs);
|
|
51
|
+
return () => h('symbiote-text', {}, 'sensor');
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (measurement === undefined) {
|
|
56
|
+
throw new Error('setup() did not run');
|
|
57
|
+
}
|
|
58
|
+
return measurement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('useLightSensor (Vue)', () => {
|
|
62
|
+
it('starts null before any measurement arrives', () => {
|
|
63
|
+
const measurement = mountLightSensor();
|
|
64
|
+
|
|
65
|
+
expect(measurement.value).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('updates the ref when the native listener fires', () => {
|
|
69
|
+
const measurement = mountLightSensor();
|
|
70
|
+
const reading: ILightSensorMeasurement = { illuminance: 42, timestamp: 123 };
|
|
71
|
+
|
|
72
|
+
registeredListener?.(reading);
|
|
73
|
+
|
|
74
|
+
expect(measurement.value).toEqual(reading);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('removes the subscription on unmount', () => {
|
|
78
|
+
mountLightSensor();
|
|
79
|
+
unmount(ROOT_TAG);
|
|
80
|
+
|
|
81
|
+
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('sets the update interval once at subscribe time when provided', () => {
|
|
85
|
+
mountLightSensor(50);
|
|
86
|
+
|
|
87
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledWith(50);
|
|
88
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('does not touch the update interval when omitted', () => {
|
|
92
|
+
mountLightSensor();
|
|
93
|
+
|
|
94
|
+
expect(setUpdateIntervalMock).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic Magnetometer singleton (core/) — mirrors
|
|
2
|
+
// the lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of use-color-scheme.ts's subscription handle. Unlike
|
|
4
|
+
// use-hide-animation.ts (which takes a config getter because its consumer's config changes
|
|
5
|
+
// across reactive updates), this subscribes exactly once at mount and never needs to react to
|
|
6
|
+
// a later change of updateIntervalMs, so a plain numeric param is enough.
|
|
7
|
+
|
|
8
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
9
|
+
import { Magnetometer, type EventSubscription, type IMagnetometerMeasurement } from '../../../core';
|
|
10
|
+
|
|
11
|
+
export function useMagnetometer(updateIntervalMs?: number): Ref<IMagnetometerMeasurement | null> {
|
|
12
|
+
// A plain ref: the value is a POJO measurement, not an engine node, so no shallowRef needed.
|
|
13
|
+
const measurement = ref<IMagnetometerMeasurement | null>(null);
|
|
14
|
+
let subscription: EventSubscription | undefined;
|
|
15
|
+
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
if (updateIntervalMs !== undefined) {
|
|
18
|
+
Magnetometer.setUpdateInterval(updateIntervalMs);
|
|
19
|
+
}
|
|
20
|
+
subscription = Magnetometer.addListener(next => {
|
|
21
|
+
measurement.value = next;
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => {
|
|
26
|
+
subscription?.remove();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return measurement;
|
|
30
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Co-located Vue-driven test (ADR 0025) for useMagnetometer. Mocks the whole core module
|
|
2
|
+
// (never expo-modules-core internals) since this exercises composable mount/unmount lifecycle
|
|
3
|
+
// timing, not any native view — there is none here, so no ViewConfig fixture is needed.
|
|
4
|
+
|
|
5
|
+
import { defineComponent, h, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { mount, unmount } from '@symbiote-native/vue';
|
|
8
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
9
|
+
import type { IMagnetometerMeasurement } from '../../../core';
|
|
10
|
+
import { useMagnetometer } from './index';
|
|
11
|
+
|
|
12
|
+
const ROOT_TAG = 9822;
|
|
13
|
+
|
|
14
|
+
type IListener = (measurement: IMagnetometerMeasurement) => void;
|
|
15
|
+
|
|
16
|
+
let registeredListener: IListener | undefined;
|
|
17
|
+
const removeMock = vi.fn();
|
|
18
|
+
const addListenerMock = vi.fn((listener: IListener) => {
|
|
19
|
+
registeredListener = listener;
|
|
20
|
+
return { remove: removeMock };
|
|
21
|
+
});
|
|
22
|
+
const setUpdateIntervalMock = vi.fn();
|
|
23
|
+
|
|
24
|
+
vi.mock('../../../core', () => ({
|
|
25
|
+
Magnetometer: {
|
|
26
|
+
addListener: (listener: IListener) => addListenerMock(listener),
|
|
27
|
+
removeAllListeners: vi.fn(),
|
|
28
|
+
setUpdateInterval: (intervalMs: number) => setUpdateIntervalMock(intervalMs),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const fabric = installFabric();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
fabric.reset();
|
|
36
|
+
registeredListener = undefined;
|
|
37
|
+
addListenerMock.mockClear();
|
|
38
|
+
removeMock.mockClear();
|
|
39
|
+
setUpdateIntervalMock.mockClear();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
43
|
+
|
|
44
|
+
function mountMagnetometer(updateIntervalMs?: number): Ref<IMagnetometerMeasurement | null> {
|
|
45
|
+
let measurement: Ref<IMagnetometerMeasurement | null> | undefined;
|
|
46
|
+
mount(
|
|
47
|
+
ROOT_TAG,
|
|
48
|
+
defineComponent({
|
|
49
|
+
setup: () => {
|
|
50
|
+
measurement = useMagnetometer(updateIntervalMs);
|
|
51
|
+
return () => h('symbiote-text', {}, 'sensor');
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (measurement === undefined) {
|
|
56
|
+
throw new Error('setup() did not run');
|
|
57
|
+
}
|
|
58
|
+
return measurement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('useMagnetometer (Vue)', () => {
|
|
62
|
+
it('starts null before any measurement arrives', () => {
|
|
63
|
+
const measurement = mountMagnetometer();
|
|
64
|
+
|
|
65
|
+
expect(measurement.value).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('updates the ref when the native listener fires', () => {
|
|
69
|
+
const measurement = mountMagnetometer();
|
|
70
|
+
const reading: IMagnetometerMeasurement = { x: 0.1, y: 0.2, z: 0.9, timestamp: 123 };
|
|
71
|
+
|
|
72
|
+
registeredListener?.(reading);
|
|
73
|
+
|
|
74
|
+
expect(measurement.value).toEqual(reading);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('removes the subscription on unmount', () => {
|
|
78
|
+
mountMagnetometer();
|
|
79
|
+
unmount(ROOT_TAG);
|
|
80
|
+
|
|
81
|
+
expect(removeMock).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('sets the update interval once at subscribe time when provided', () => {
|
|
85
|
+
mountMagnetometer(50);
|
|
86
|
+
|
|
87
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledWith(50);
|
|
88
|
+
expect(setUpdateIntervalMock).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('does not touch the update interval when omitted', () => {
|
|
92
|
+
mountMagnetometer();
|
|
93
|
+
|
|
94
|
+
expect(setUpdateIntervalMock).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic MagnetometerUncalibrated singleton (core/) —
|
|
2
|
+
// mirrors the lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of use-color-scheme.ts's subscription handle. Unlike
|
|
4
|
+
// use-hide-animation.ts (which takes a config getter because its consumer's config changes
|
|
5
|
+
// across reactive updates), this subscribes exactly once at mount and never needs to react to
|
|
6
|
+
// a later change of updateIntervalMs, so a plain numeric param is enough.
|
|
7
|
+
|
|
8
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
9
|
+
import {
|
|
10
|
+
MagnetometerUncalibrated,
|
|
11
|
+
type EventSubscription,
|
|
12
|
+
type IMagnetometerUncalibratedMeasurement,
|
|
13
|
+
} from '../../../core';
|
|
14
|
+
|
|
15
|
+
export function useMagnetometerUncalibrated(
|
|
16
|
+
updateIntervalMs?: number,
|
|
17
|
+
): Ref<IMagnetometerUncalibratedMeasurement | null> {
|
|
18
|
+
// A plain ref: the value is a POJO measurement, not an engine node, so no shallowRef needed.
|
|
19
|
+
const measurement = ref<IMagnetometerUncalibratedMeasurement | null>(null);
|
|
20
|
+
let subscription: EventSubscription | undefined;
|
|
21
|
+
|
|
22
|
+
onMounted(() => {
|
|
23
|
+
if (updateIntervalMs !== undefined) {
|
|
24
|
+
MagnetometerUncalibrated.setUpdateInterval(updateIntervalMs);
|
|
25
|
+
}
|
|
26
|
+
subscription = MagnetometerUncalibrated.addListener(next => {
|
|
27
|
+
measurement.value = next;
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
onUnmounted(() => {
|
|
32
|
+
subscription?.remove();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return measurement;
|
|
36
|
+
}
|