diff --git a/App.test.tsx b/App.test.tsx index 17f96c9..38a1d72 100644 --- a/App.test.tsx +++ b/App.test.tsx @@ -4,6 +4,7 @@ import Home from './src/screens/Home'; import * as Location from 'expo-location'; import {getOrCreateRealtimeRecord} from './src/lib/data'; import {startRide} from './src/lib/ride'; +import {RideModel, RealtimeDataModel} from './src/database'; it('App renders correctly for signed user.', async () => { // check the home pages renders @@ -17,6 +18,7 @@ it('App renders correctly for signed user.', async () => { it('App registers location service and logs to db with distance calculated with active ride', async () => { let tree!: ReactTestRenderer; + let record!: RealtimeDataModel; await renderer.act(() => { tree = renderer.create(); }); @@ -44,7 +46,9 @@ it('App registers location service and logs to db with distance calculated with Location._emitLocation(newLocation); }); - let record = await getOrCreateRealtimeRecord(); + await renderer.act(async () => { + record = await getOrCreateRealtimeRecord(); + }); expect(record.distance).toBe(0); expect(record.latitude).toBe(newLocation.coords.latitude); expect(record.longitude).toBe(newLocation.coords.longitude); @@ -79,8 +83,80 @@ it('App registers location service and logs to db with distance calculated with tree.unmount(); }); +it('MovingTime correctly handles locations recorded before the ride start.', async () => { + let tree!: ReactTestRenderer; + let ride!: RideModel; + let record!: RealtimeDataModel; + + const coords = { + accuracy: 110, + latitude: 41.4027, + longitude: 2.1743, + heading: 10, + altitude: 41.0, + altitudeAccuracy: 0, + }; + + await renderer.act(async () => { + tree = renderer.create(); + }); + + tree.root.findByType(Home); + + await renderer.act(async () => { + record = await getOrCreateRealtimeRecord(); + }); + + const startTime = Date.now(); + + // Trigger a location update + // before starting ride + await renderer.act(async () => { + // @ts-ignore + // this is a mock method + await Location._emitLocation({ + timestamp: startTime - 5000, + mocked: true, + coords: { + ...coords, + speed: 1, + }, + }); + }); + + await renderer.act(async () => { + // ensure there is an active ride + ride = await startRide(); + // @ts-ignore + // this is a mock method + }); + + // Trigger a location update + // during ride + await renderer.act(async () => { + // @ts-ignore + // this is a mock method + await Location._emitLocation({ + timestamp: ride.startedAt.getTime() + 1000, + mocked: true, + coords: { + ...coords, + speed: 1, + }, + }); + }); + + // now ensure record.movingTime is back to zero. + // and doesn't take the location recorded + // before ride start into account. + expect(record.ride!.id).toBeTruthy(); + expect(record.movingTime).toBe(1000); +}); + it('App registers location service and logs to db with movingTime calculated with active ride', async () => { let tree!: ReactTestRenderer; + let record!: RealtimeDataModel; + const coords = { accuracy: 110, latitude: 41.4027, @@ -96,7 +172,6 @@ it('App registers location service and logs to db with movingTime calculated wit tree.root.findByType(Home); - // Trigger a location update. await renderer.act(async () => { // ensure there is an active ride await startRide(); @@ -104,7 +179,9 @@ it('App registers location service and logs to db with movingTime calculated wit // this is a mock method }); - const record = await getOrCreateRealtimeRecord(); + await renderer.act(async () => { + record = await getOrCreateRealtimeRecord(); + }); expect(record.movingTime).toBe(0); expect(record.lastLocationAt).toBe(null); const startTime = Date.now(); @@ -138,7 +215,6 @@ it('App registers location service and logs to db with movingTime calculated wit }); }); - // check that expect(record.movingTime).toBe(1000); // Trigger a location update. @@ -155,7 +231,6 @@ it('App registers location service and logs to db with movingTime calculated wit }); }); - // check that expect(record.movingTime).toBe(2000); // Trigger a location update. @@ -176,12 +251,13 @@ it('App registers location service and logs to db with movingTime calculated wit // because speed is == 0 expect(record.movingTime).toBe(2000); - // Now check for record in realtime db. tree.unmount(); }); it('App registers location service and logs to db with without movingTime calculated with inactive ride', async () => { let tree!: ReactTestRenderer; + let record!: RealtimeDataModel; + const coords = { accuracy: 110, latitude: 41.4027, @@ -197,7 +273,9 @@ it('App registers location service and logs to db with without movingTime calcul tree.root.findByType(Home); - const record = await getOrCreateRealtimeRecord(); + await renderer.act(async () => { + record = await getOrCreateRealtimeRecord(); + }); expect(record.movingTime).toBe(0); expect(record.lastLocationAt).toBe(null); @@ -240,6 +318,8 @@ it('App registers location service and logs to db with without movingTime calcul it('App registers location service and logs to db without distance calculated with inactive ride', async () => { let tree!: ReactTestRenderer; + let record!: RealtimeDataModel; + await renderer.act(() => { tree = renderer.create(); }); @@ -265,8 +345,9 @@ it('App registers location service and logs to db without distance calculated wi Location._emitLocation(newLocation); }); - let record = await getOrCreateRealtimeRecord(); - + await renderer.act(async () => { + record = await getOrCreateRealtimeRecord(); + }); expect(record.distance).toBe(0); expect(record.latitude).toBe(newLocation.coords.latitude); expect(record.longitude).toBe(newLocation.coords.longitude); diff --git a/setup.ts b/setup.ts index 84c99dc..4b7a998 100644 --- a/setup.ts +++ b/setup.ts @@ -1,5 +1,6 @@ import 'react-native-gesture-handler/jestSetup'; +jest.useFakeTimers(); jest.mock( '@nozbe/watermelondb/adapters/sqlite/makeDispatcher/index.native.js', () => { diff --git a/src/components/MapFollowLocation/index.test.tsx b/src/components/MapFollowLocation/index.test.tsx index 581a245..a4d094e 100644 --- a/src/components/MapFollowLocation/index.test.tsx +++ b/src/components/MapFollowLocation/index.test.tsx @@ -8,7 +8,7 @@ jest.mock('@react-navigation/elements', () => ({ it('map renders correctly', async () => { // not much to test on this. let tree!: ReactTestRenderer; - await renderer.act(() => { + renderer.act(() => { tree = renderer.create(); }); tree.root.findByType(MapWidget); diff --git a/src/lib/data/movingTime.ts b/src/lib/data/movingTime.ts index 3411039..c2585fb 100644 --- a/src/lib/data/movingTime.ts +++ b/src/lib/data/movingTime.ts @@ -2,10 +2,10 @@ import {LocationObject} from 'expo-location'; import {RealtimeDataModel} from '../../database'; import constants from '../../constants'; -export function accumulateMovingTime( +export async function accumulateMovingTime( lastRealTimeRecord: RealtimeDataModel, currentLocation: LocationObject, -): number { +): Promise { // If we don't have a speed we return the previous // if we have stopped we return the previous value if ( @@ -13,9 +13,17 @@ export function accumulateMovingTime( currentLocation.coords.speed < constants.movingSpeed || !lastRealTimeRecord.lastLocationAt ) { + // we need to ensure that the return lastRealTimeRecord.movingTime; } + const ride = await lastRealTimeRecord.ride?.fetch(); + + if (ride && lastRealTimeRecord.lastLocationAt < ride?.startedAt) { + // check if we have a ride but this is the first location + return currentLocation.timestamp - ride.startedAt.getTime(); + } + // we are moving and have speed. // we should increment the movingTime const diff = diff --git a/src/lib/data/realtime.ts b/src/lib/data/realtime.ts index e99e279..7fb7436 100644 --- a/src/lib/data/realtime.ts +++ b/src/lib/data/realtime.ts @@ -57,7 +57,7 @@ export async function onLocation( : 0; const movingTime = realtimeData.ride?.id - ? accumulateMovingTime(realtimeData, location) + ? await accumulateMovingTime(realtimeData, location) : 0; console.log('accumulated distance: ', distance);