@@ -405,4 +405,104 @@ describe('xiaohongshu publish', () => {
405405 } ,
406406 ] ) ;
407407 } ) ;
408+ it ( 'treats 保存成功 on the draft list as a successful draft save' , async ( ) => {
409+ const cmd = getRegistry ( ) . get ( 'xiaohongshu/publish' ) ;
410+ expect ( cmd ?. func ) . toBeTypeOf ( 'function' ) ;
411+ const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'opencli-xhs-publish-' ) ) ;
412+ const imagePath = path . join ( tempDir , 'demo.jpg' ) ;
413+ fs . writeFileSync ( imagePath , Buffer . from ( [ 0xff , 0xd8 , 0xff , 0xd9 ] ) ) ;
414+ const page = createConditionalPageMock ( ( code ) => {
415+ if ( code . includes ( 'location.href' ) )
416+ return 'https://creator.xiaohongshu.com/publish/publish?from=menu_left&target=image' ;
417+ if ( code . includes ( "const targets = ['上传图文', '图文', '图片']" ) )
418+ return { ok : true , target : '上传图文' , text : '上传图文' } ;
419+ if ( code . includes ( 'hasTitleInput' ) && code . includes ( 'hasVideoSurface' ) )
420+ return { state : 'editor_ready' , hasTitleInput : true , hasImageInput : true , hasVideoSurface : false } ;
421+ if ( code . includes ( 'const images =' ) && code . includes ( 'dt.items.add(new File' ) )
422+ return { ok : true , count : 1 } ;
423+ if ( code . includes ( '[class*="upload"][class*="progress"]' ) )
424+ return false ;
425+ if ( code . includes ( 'const sels =' ) && code . includes ( 'for (const sel of sels)' ) )
426+ return true ;
427+ if ( code . includes ( '__opencli_xhs_fill_phase' ) && code . includes ( '"locate"' ) ) {
428+ return code . includes ( '[contenteditable="true"][class*="content"]' )
429+ ? { ok : true , sel : '[contenteditable="true"][class*="content"]' , kind : 'contenteditable' }
430+ : { ok : true , sel : 'input[placeholder*="标题"]' , kind : 'input' } ;
431+ }
432+ if ( code . includes ( '__opencli_xhs_fill_phase' ) && code . includes ( '"apply"' ) ) {
433+ return code . includes ( '[contenteditable="true"][class*="content"]' )
434+ ? { ok : true , actual : '停留在发布页也算成功' }
435+ : { ok : true , actual : '草稿成功提示' } ;
436+ }
437+ if ( code . includes ( 'labels.some' ) )
438+ return true ;
439+ if ( code . includes ( 'for (const el of document.querySelectorAll' ) ) {
440+ return code . includes ( '保存成功' ) ? '保存成功' : '' ;
441+ }
442+ throw new Error ( `Unhandled evaluate call: ${ code . slice ( 0 , 120 ) } ` ) ;
443+ } ) ;
444+ const result = await cmd . func ( page , {
445+ title : '草稿成功提示' ,
446+ content : '停留在发布页也算成功' ,
447+ images : imagePath ,
448+ topics : '' ,
449+ draft : true ,
450+ } ) ;
451+ expect ( result ) . toEqual ( [
452+ {
453+ status : '✅ 暂存成功' ,
454+ detail : '"草稿成功提示" · 1张图片 · 保存成功' ,
455+ } ,
456+ ] ) ;
457+ } ) ;
458+ it ( 'does not treat 保存成功 alone as a publish success signal' , async ( ) => {
459+ const cmd = getRegistry ( ) . get ( 'xiaohongshu/publish' ) ;
460+ expect ( cmd ?. func ) . toBeTypeOf ( 'function' ) ;
461+ const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'opencli-xhs-publish-' ) ) ;
462+ const imagePath = path . join ( tempDir , 'demo.jpg' ) ;
463+ fs . writeFileSync ( imagePath , Buffer . from ( [ 0xff , 0xd8 , 0xff , 0xd9 ] ) ) ;
464+ const page = createConditionalPageMock ( ( code ) => {
465+ if ( code . includes ( 'location.href' ) )
466+ return 'https://creator.xiaohongshu.com/publish/publish?from=menu_left&target=image' ;
467+ if ( code . includes ( "const targets = ['上传图文', '图文', '图片']" ) )
468+ return { ok : true , target : '上传图文' , text : '上传图文' } ;
469+ if ( code . includes ( 'hasTitleInput' ) && code . includes ( 'hasVideoSurface' ) )
470+ return { state : 'editor_ready' , hasTitleInput : true , hasImageInput : true , hasVideoSurface : false } ;
471+ if ( code . includes ( 'const images =' ) && code . includes ( 'dt.items.add(new File' ) )
472+ return { ok : true , count : 1 } ;
473+ if ( code . includes ( '[class*="upload"][class*="progress"]' ) )
474+ return false ;
475+ if ( code . includes ( 'const sels =' ) && code . includes ( 'for (const sel of sels)' ) )
476+ return true ;
477+ if ( code . includes ( '__opencli_xhs_fill_phase' ) && code . includes ( '"locate"' ) ) {
478+ return code . includes ( '[contenteditable="true"][class*="content"]' )
479+ ? { ok : true , sel : '[contenteditable="true"][class*="content"]' , kind : 'contenteditable' }
480+ : { ok : true , sel : 'input[placeholder*="标题"]' , kind : 'input' } ;
481+ }
482+ if ( code . includes ( '__opencli_xhs_fill_phase' ) && code . includes ( '"apply"' ) ) {
483+ return code . includes ( '[contenteditable="true"][class*="content"]' )
484+ ? { ok : true , actual : '发布提示不该复用草稿成功' }
485+ : { ok : true , actual : '发布成功提示' } ;
486+ }
487+ if ( code . includes ( 'labels.some' ) )
488+ return true ;
489+ if ( code . includes ( 'for (const el of document.querySelectorAll' ) ) {
490+ return code . includes ( '保存成功' ) ? '保存成功' : '' ;
491+ }
492+ throw new Error ( `Unhandled evaluate call: ${ code . slice ( 0 , 120 ) } ` ) ;
493+ } ) ;
494+ const result = await cmd . func ( page , {
495+ title : '发布成功提示' ,
496+ content : '发布提示不该复用草稿成功' ,
497+ images : imagePath ,
498+ topics : '' ,
499+ draft : false ,
500+ } ) ;
501+ expect ( result ) . toEqual ( [
502+ {
503+ status : '⚠️ 操作完成,请在浏览器中确认' ,
504+ detail : '"发布成功提示" · 1张图片 · https://creator.xiaohongshu.com/publish/publish?from=menu_left&target=image' ,
505+ } ,
506+ ] ) ;
507+ } ) ;
408508} ) ;
0 commit comments