@@ -8,7 +8,7 @@ import { type Files } from '@/models/common/file'
88import type { CloudHelpers } from '@/models/common/cloud'
99import { mockFile , MockProject } from '@/models/common/test'
1010import type { IProject , ProjectSerialized } from '@/models/project'
11- import { Editing , SavingState , EditingMode , type ILocalCache , type UIHelpersForLoadingProject } from './editing'
11+ import { Editing , SavingState , EditingMode , type ILocalCache , type LoadProjectParams , type UIHelpersForLoadingProject } from './editing'
1212
1313function makeFiles ( ) {
1414 return {
@@ -284,6 +284,10 @@ describe('Editing.loadProject', () => {
284284 }
285285 }
286286
287+ function makeLoadProjectParams ( ownerInput = 'alice' , projectNameInput = 'my-project' ) : LoadProjectParams {
288+ return { ownerInput, projectNameInput }
289+ }
290+
287291 function makeSerialized ( owner : string , name : string , version ?: number ) : ProjectSerialized {
288292 return {
289293 metadata : { owner, name, version } ,
@@ -301,7 +305,7 @@ describe('Editing.loadProject', () => {
301305 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
302306
303307 const ac = new AbortController ( )
304- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
308+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
305309
306310 expect ( cloudHelper . load ) . toHaveBeenCalledWith ( 'alice' , 'my-project' , false , ac . signal )
307311 expect ( project . load ) . toHaveBeenCalledWith ( cloudData , ac . signal )
@@ -318,7 +322,7 @@ describe('Editing.loadProject', () => {
318322 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
319323
320324 const ac = new AbortController ( )
321- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
325+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
322326
323327 expect ( cloudHelper . load ) . toHaveBeenCalledWith ( 'alice' , 'my-project' , false , ac . signal )
324328 expect ( project . load ) . toHaveBeenCalledWith ( cloudData , ac . signal )
@@ -335,7 +339,7 @@ describe('Editing.loadProject', () => {
335339 const project = makeProject ( { owner : 'alice' , name : 'my-project' } )
336340 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
337341
338- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
342+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
339343
340344 expect ( project . load ) . toHaveBeenCalledWith ( localData , expect . anything ( ) )
341345 } )
@@ -350,7 +354,7 @@ describe('Editing.loadProject', () => {
350354 const project = makeProject ( { owner : 'alice' , name : 'my-project' } )
351355 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
352356
353- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
357+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
354358
355359 expect ( project . load ) . toHaveBeenCalledWith ( cloudData , expect . anything ( ) )
356360 expect ( localCacheHelper . clear ) . toHaveBeenCalled ( )
@@ -366,7 +370,7 @@ describe('Editing.loadProject', () => {
366370 const project = makeProject ( { owner : 'alice' , name : 'my-project' } )
367371 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
368372
369- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
373+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
370374
371375 expect ( localCacheHelper . clear ) . toHaveBeenCalled ( )
372376 expect ( project . load ) . toHaveBeenCalledWith ( cloudData , expect . anything ( ) )
@@ -385,7 +389,7 @@ describe('Editing.loadProject', () => {
385389 const helpers = makeUIHelpers ( )
386390 vi . mocked ( helpers . confirmOpenTargetWithAnotherInCache ) . mockResolvedValue ( true )
387391
388- await editing . loadProject ( helpers , makeReporter ( ) , new AbortController ( ) . signal )
392+ await editing . loadProject ( makeLoadProjectParams ( ) , helpers , makeReporter ( ) , new AbortController ( ) . signal )
389393
390394 expect ( helpers . confirmOpenTargetWithAnotherInCache ) . toHaveBeenCalledWith ( 'my-project' , 'other-project' )
391395 expect ( localCacheHelper . clear ) . toHaveBeenCalled ( )
@@ -404,7 +408,7 @@ describe('Editing.loadProject', () => {
404408
405409 const helpers = makeUIHelpers ( )
406410
407- await editing . loadProject ( helpers , makeReporter ( ) , new AbortController ( ) . signal )
411+ await editing . loadProject ( makeLoadProjectParams ( ) , helpers , makeReporter ( ) , new AbortController ( ) . signal )
408412
409413 expect ( helpers . confirmOpenTargetWithAnotherInCache ) . not . toHaveBeenCalled ( )
410414 expect ( localCacheHelper . clear ) . not . toHaveBeenCalled ( )
@@ -424,19 +428,23 @@ describe('Editing.loadProject', () => {
424428 const helpers = makeUIHelpers ( )
425429 vi . mocked ( helpers . confirmOpenTargetWithAnotherInCache ) . mockResolvedValue ( false )
426430
427- await expect ( editing . loadProject ( helpers , makeReporter ( ) , new AbortController ( ) . signal ) ) . rejects . toThrow ( Cancelled )
431+ await expect ( editing . loadProject ( makeLoadProjectParams ( ) , helpers , makeReporter ( ) , new AbortController ( ) . signal ) ) . rejects . toThrow ( Cancelled )
428432 expect ( localCacheHelper . clear ) . not . toHaveBeenCalled ( )
429433 expect ( helpers . openProject ) . toHaveBeenCalledWith ( 'alice' , 'cached-project' )
430434 expect ( project . load ) . not . toHaveBeenCalled ( )
431435 } )
432436
433- it ( 'should throw when project has no owner or name' , async ( ) => {
437+ it ( 'should load project when the model starts without owner or name' , async ( ) => {
438+ const cloudData = makeSerialized ( 'alice' , 'my-project' , 1 )
439+ const cloudHelper = makeCloudHelper ( )
440+ vi . mocked ( cloudHelper . load ) . mockResolvedValue ( cloudData )
434441 const project = new MockProject ( undefined , undefined , makeFiles ( ) )
435- const editing = makeEditing ( { project } )
442+ const editing = makeEditing ( { project, cloudHelper , signedInUsername : 'alice' } )
436443
437- await expect ( editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal ) ) . rejects . toThrow (
438- 'Project owner and name expected'
439- )
444+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
445+
446+ expect ( project . load ) . toHaveBeenCalledWith ( cloudData , expect . anything ( ) )
447+ expect ( editing . mode ) . toBe ( EditingMode . AutoSave )
440448 } )
441449
442450 it ( 'should set preferPublishedContent to false when signed-in user is the owner' , async ( ) => {
@@ -449,7 +457,7 @@ describe('Editing.loadProject', () => {
449457 const editing = new Editing ( project , cloudHelper , localCacheHelper , ( ) => true , 'alice' )
450458
451459 const ac = new AbortController ( )
452- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
460+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
453461
454462 expect ( cloudHelper . load ) . toHaveBeenCalledWith ( 'alice' , 'my-project' , false , ac . signal )
455463 } )
@@ -464,11 +472,30 @@ describe('Editing.loadProject', () => {
464472 const editing = new Editing ( project , cloudHelper , localCacheHelper , ( ) => true , 'bob' )
465473
466474 const ac = new AbortController ( )
467- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
475+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
468476
469477 expect ( cloudHelper . load ) . toHaveBeenCalledWith ( 'alice' , 'my-project' , true , ac . signal )
470478 } )
471479
480+ it ( 'should treat owner input with different casing as the same owner' , async ( ) => {
481+ const cloudData = makeSerialized ( 'alice' , 'my-project' , 1 )
482+ const localData = makeSerialized ( 'alice' , 'my-project' , 2 )
483+ const cloudHelper = makeCloudHelper ( )
484+ vi . mocked ( cloudHelper . load ) . mockResolvedValue ( cloudData )
485+ const localCacheHelper = makeLocalCache ( localData )
486+
487+ const project = new MockProject ( undefined , undefined , makeFiles ( ) )
488+ const editing = makeEditing ( { project, cloudHelper, localCacheHelper, signedInUsername : 'alice' } )
489+
490+ const ac = new AbortController ( )
491+ await editing . loadProject ( makeLoadProjectParams ( 'Alice' , 'my-project' ) , makeUIHelpers ( ) , makeReporter ( ) , ac . signal )
492+
493+ expect ( cloudHelper . load ) . toHaveBeenCalledWith ( 'Alice' , 'my-project' , false , ac . signal )
494+ expect ( localCacheHelper . clear ) . not . toHaveBeenCalled ( )
495+ expect ( project . load ) . toHaveBeenCalledWith ( localData , expect . anything ( ) )
496+ expect ( editing . mode ) . toBe ( EditingMode . AutoSave )
497+ } )
498+
472499 it ( 'should prefer local cache when cloud version is undefined and local version is undefined' , async ( ) => {
473500 const cloudData = makeSerialized ( 'alice' , 'my-project' )
474501 const localData = makeSerialized ( 'alice' , 'my-project' )
@@ -479,7 +506,7 @@ describe('Editing.loadProject', () => {
479506 const project = makeProject ( { owner : 'alice' , name : 'my-project' } )
480507 const editing = makeEditing ( { project, cloudHelper, localCacheHelper } )
481508
482- await editing . loadProject ( makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
509+ await editing . loadProject ( makeLoadProjectParams ( ) , makeUIHelpers ( ) , makeReporter ( ) , new AbortController ( ) . signal )
483510
484511 // Both versions are undefined (-1 == -1), so cloudVersion > localVersion is false, local data wins
485512 expect ( project . load ) . toHaveBeenCalledWith ( localData , expect . anything ( ) )
0 commit comments