experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

test: add image content display and data flow tests

- 3 Rust tests: image null content by default, get_item_content after update, get_saved_images returns content
- 5 frontend structural tests: image editor content rendering, scrollable wrapper, content pass-through in getUnifiedItems and renderUnifiedItem

+146
+56
backend/tauri-mobile/peek-core/src/items.rs
··· 995 995 let decoded = STANDARD.decode(data.unwrap()).unwrap(); 996 996 assert_eq!(decoded, image_bytes); 997 997 } 998 + 999 + #[test] 1000 + fn test_image_has_null_content_by_default() { 1001 + let (conn, device_id) = setup_db(); 1002 + let image_bytes = b"image without content"; 1003 + let id = save_image(&conn, image_bytes, "image/jpeg", &[], None, None, None, None, &device_id).unwrap(); 1004 + 1005 + // Newly saved images should have NULL content 1006 + let images = get_saved_images(&conn).unwrap(); 1007 + assert_eq!(images.len(), 1); 1008 + assert_eq!(images[0].id, id); 1009 + assert!(images[0].content.is_none(), "Newly saved image should have NULL content"); 1010 + 1011 + // Also verify via get_item_content 1012 + let content = get_item_content(&conn, &id).unwrap(); 1013 + assert!(content.is_none(), "get_item_content should return None for new image"); 1014 + } 1015 + 1016 + #[test] 1017 + fn test_get_item_content_after_update() { 1018 + let (conn, device_id) = setup_db(); 1019 + let image_bytes = b"image for content test"; 1020 + let id = save_image(&conn, image_bytes, "image/jpeg", &[], None, None, None, None, &device_id).unwrap(); 1021 + 1022 + // Set content via update_item_content 1023 + update_item_content(&conn, &id, "OCR extracted text from image", &device_id).unwrap(); 1024 + 1025 + // get_item_content should return the content 1026 + let content = get_item_content(&conn, &id).unwrap(); 1027 + assert_eq!(content, Some("OCR extracted text from image".to_string())); 1028 + } 1029 + 1030 + #[test] 1031 + fn test_get_saved_images_returns_content_field() { 1032 + let (conn, device_id) = setup_db(); 1033 + let image_bytes = b"image with content"; 1034 + let id = save_image(&conn, image_bytes, "image/png", &["photo".to_string()], None, None, Some(640), Some(480), &device_id).unwrap(); 1035 + 1036 + // Initially no content 1037 + let images = get_saved_images(&conn).unwrap(); 1038 + assert_eq!(images.len(), 1); 1039 + assert!(images[0].content.is_none()); 1040 + 1041 + // Set content 1042 + update_item_content(&conn, &id, "A description of the image contents", &device_id).unwrap(); 1043 + 1044 + // get_saved_images should now include the content 1045 + let images = get_saved_images(&conn).unwrap(); 1046 + assert_eq!(images.len(), 1); 1047 + assert_eq!(images[0].content, Some("A description of the image contents".to_string())); 1048 + // Other fields should still be correct 1049 + assert_eq!(images[0].id, id); 1050 + assert_eq!(images[0].width, Some(640)); 1051 + assert_eq!(images[0].height, Some(480)); 1052 + assert!(images[0].tags.contains(&"photo".to_string())); 1053 + } 998 1054 }
+90
backend/tauri-mobile/tests/editor-consistency.test.js
··· 50 50 ); 51 51 }); 52 52 }); 53 + 54 + describe('Image editor content display', () => { 55 + // Extract the image editor overlay rendering function body 56 + const editorImageSection = (() => { 57 + // Find the renderEditingOverlay or similar section that handles image editing 58 + // The image editor is inside a block that checks editingImageId 59 + const imageEditorPattern = /editor-image-preview[^]*?EditorButtons/s; 60 + const match = appSource.match(imageEditorPattern); 61 + return match ? match[0] : ''; 62 + })(); 63 + 64 + it('image editor renders content when item.content is present', () => { 65 + // The image editor overlay should reference item.content 66 + assert.ok( 67 + editorImageSection.includes('item.content'), 68 + 'Image editor overlay must reference item.content to display content text' 69 + ); 70 + // Verify there is a conditional render for content 71 + assert.ok( 72 + editorImageSection.includes('item.content &&'), 73 + 'Image editor must conditionally render content (item.content && ...)' 74 + ); 75 + }); 76 + 77 + it('image editor content is inside a scrollable wrapper (editor-image-scrollable)', () => { 78 + // The scrollable div must wrap the content and tags section 79 + assert.ok( 80 + editorImageSection.includes('editor-image-scrollable'), 81 + 'Image editor must have editor-image-scrollable wrapper class' 82 + ); 83 + // Verify the scrollable div comes before content and tags 84 + const scrollableIdx = editorImageSection.indexOf('editor-image-scrollable'); 85 + const contentIdx = editorImageSection.indexOf('edit-image-content'); 86 + const tagsSectionIdx = editorImageSection.indexOf('TagsSection'); 87 + assert.ok(scrollableIdx < contentIdx, 88 + 'editor-image-scrollable must appear before edit-image-content'); 89 + assert.ok(scrollableIdx < tagsSectionIdx, 90 + 'editor-image-scrollable must appear before TagsSection'); 91 + }); 92 + 93 + it('getUnifiedItems passes content field for image items', () => { 94 + // Find the getUnifiedItems function body 95 + const getUnifiedPattern = /const getUnifiedItems = \(\)[^]*?(?=\n const \w+ = )/s; 96 + const match = appSource.match(getUnifiedPattern); 97 + assert.ok(match, 'getUnifiedItems function not found'); 98 + 99 + // Within the image section, content must be passed from image.content 100 + const imageSection = match[0].match(/showType\("image"\)[^]*?}\);/s); 101 + assert.ok(imageSection, 'Image section in getUnifiedItems not found'); 102 + assert.ok( 103 + imageSection[0].includes('content: image.content'), 104 + 'getUnifiedItems must pass content: image.content for image items' 105 + ); 106 + }); 107 + 108 + it('renderUnifiedItem passes content to renderImageItem for image type', () => { 109 + // Find renderUnifiedItem function body 110 + const renderUnifiedPattern = /const renderUnifiedItem = \(item: UnifiedItem\)[^]*?(?=\n (?:const|\/\/))/s; 111 + const match = appSource.match(renderUnifiedPattern); 112 + assert.ok(match, 'renderUnifiedItem function not found'); 113 + 114 + // The image case must pass content field 115 + const imageCasePattern = /case "image":[^]*?renderImageItem\(\{[^}]*\}/s; 116 + const imageCase = match[0].match(imageCasePattern); 117 + assert.ok(imageCase, 'Image case in renderUnifiedItem not found'); 118 + assert.ok( 119 + imageCase[0].includes('content: item.content'), 120 + 'renderUnifiedItem must pass content: item.content to renderImageItem' 121 + ); 122 + }); 123 + }); 124 + 125 + describe('Image card content display', () => { 126 + it('renderImageItem shows content text on image cards', () => { 127 + // Find the renderImageItem function 128 + const renderImagePattern = /const renderImageItem = \(item: SavedImage\)[^]*?(?=\n const \w+ = )/s; 129 + const match = appSource.match(renderImagePattern); 130 + assert.ok(match, 'renderImageItem function not found'); 131 + 132 + // Must conditionally render item.content 133 + assert.ok( 134 + match[0].includes('item.content'), 135 + 'renderImageItem must reference item.content' 136 + ); 137 + assert.ok( 138 + match[0].includes('card-content'), 139 + 'renderImageItem must render content in a card-content div' 140 + ); 141 + }); 142 + });