also looking at this
feat: native trail maps and complete native mobile screens
#1017
60 files
+2505
-823
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -40,6 +40,49 @@ describe('native Record checkpoint recovery',()=>{ | ||
| 40 | 40 | expect(requests(screen).some(r=>r.payload.module==='Network')).toBe(false) |
| 41 | 41 | expect(shownText(screen).some(text=>text.includes('moving ·'))).toBe(true) |
| 42 | 42 | }) |
| 43 | it('retains an existing checkpoint when native registration loses a race',async()=>{ | |
| 44 | const screen=await start('Record',{},['fetch','secureStorage','storage','storageCompareAndSet','storageSetIfAbsent','crypto','geolocation','locationRecordingOwnership','locationRecordingIntentIdentity','lifecycle'],new Map([['auth_token','record-token'],['wildloop-account',JSON.stringify({token:'record-token',user:{id:7}})]])) | |
| 45 | const stored=await waitForRequest(screen,0,r=>r.payload.module==='Storage' && r.payload.method==='get') | |
| 46 | answer(screen,stored,null) | |
| 47 | const initial=await waitForRequest(screen,0,r=>r.payload.method==='getRecordingState') | |
| 48 | answer(screen,initial,{active:false,paused:false}) | |
| 49 | await Bun.sleep(0) | |
| 50 | await screen.event('record-start','onPress') | |
| 51 | const host=await waitForRequest(screen,requests(screen).indexOf(initial)+1,r=>r.payload.method==='getRecordingState') | |
| 52 | answer(screen,host,{active:false,paused:false}) | |
| 53 | const uuid=await waitForRequest(screen,0,r=>r.payload.module==='Crypto') | |
| 54 | answer(screen,uuid,'803798f7-733a-4692-9ca5-6dca46acc6e2') | |
| 55 | const create=await waitForRequest(screen,0,r=>r.payload.method==='setIfAbsent') | |
| 56 | answer(screen,create,false) | |
| 57 | const replace=await waitForRequest(screen,0,r=>r.payload.method==='compareAndSet') | |
| 58 | expect(replace.payload.args[1]).toBeNull() | |
| 59 | answer(screen,replace,false) | |
| 60 | await waitForText(screen,'The saved recording changed on this device. Pull down to recover it before trying again. Your track has been retained.') | |
| 61 | expect(requests(screen).some(r=>r.payload.method==='startRecording' || r.payload.method==='set' || r.payload.method==='remove')).toBe(false) | |
| 62 | }) | |
| 63 | it('acknowledges only the completed owner and never clears a replaced checkpoint',async()=>{ | |
| 64 | const saved={...checkpoint,phase:'stopped',endedAt:160000} | |
| 65 | const screen=await start('Record',{},['fetch','secureStorage','storage','storageCompareAndSet','geolocation','locationRecordingOwnership','lifecycle'],new Map([['auth_token','record-token'],['wildloop-account',JSON.stringify({token:'record-token',user:{id:7}})]])) | |
| 66 | const stored=await waitForRequest(screen,0,r=>r.payload.module==='Storage' && r.payload.method==='get') | |
| 67 | answer(screen,stored,saved) | |
| 68 | await waitForText(screen,'Your finished recording is saved on this device. Retry the upload when connected.') | |
| 69 | await screen.event('record-retry','onPress') | |
| 70 | const me=await waitForRequest(screen,0,r=>r.payload.module==='Network') | |
| 71 | answer(screen,me,ok({user:{id:7}})) | |
| 72 | const post=await waitForRequest(screen,requests(screen).indexOf(me)+1,r=>r.payload.module==='Network') | |
| 73 | expect(requests(screen).some(r=>r.payload.method==='acknowledgeRecording')).toBe(false) | |
| 74 | answer(screen,post,ok({activity:{id:99,captureEligible:false}},201)) | |
| 75 | const ack=await waitForRequest(screen,0,r=>r.payload.method==='acknowledgeRecording') | |
| 76 | expect(ack.payload.args[0]).toEqual({expectedId:'run-7'}) | |
| 77 | expect(requests(screen).some(r=>r.payload.method==='compareAndSet')).toBe(false) | |
| 78 | answer(screen,ack,true) | |
| 79 | const clear=await waitForRequest(screen,0,r=>r.payload.method==='compareAndSet') | |
| 80 | expect(clear.payload.args).toEqual(['wildloop-native-recording-v1',saved,null]) | |
| 81 | answer(screen,clear,false) | |
| 82 | await waitForText(screen,'The saved recording changed on this device. Pull down to recover it before trying again. Your track has been retained.') | |
| 83 | expect(requests(screen).some(r=>r.payload.method==='remove')).toBe(false) | |
| 84 | expect(screen.sent.some(r=>r.type==='NAVIGATE')).toBe(false) | |
| 85 | }) | |
| 43 | 86 | it('does not reveal or upload another account’s saved track',async()=>{ |
| 44 | 87 | const screen=await recover(8) |
| 45 | 88 | await waitForText(screen,'Log in as the account that started the saved recording before resuming or uploading it.') |