Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
72164a0
feat: Add POST method file sharing support to Share Target API
kevalyq Nov 15, 2025
57b54a4
docs: Update CHANGELOG for Share Target POST file sharing
kevalyq Nov 15, 2025
9ef42cb
fix: Wrap ShareTarget tests with I18nProvider to fix test failures
kevalyq Nov 15, 2025
01b9540
fix: Sanitize URLs to prevent XSS and open redirect attacks
kevalyq Nov 15, 2025
94085c3
security: Fix XSS and URL redirect vulnerabilities in ShareTarget
kevalyq Nov 15, 2025
7fc47f7
test: Fix Vitest pool config and ShareTarget test suite
kevalyq Nov 15, 2025
fd93519
fix: Use test:run instead of test in preflight hook
kevalyq Nov 15, 2025
7b10085
fix: Address copilot review suggestions for ShareTarget & SW
kevalyq Nov 15, 2025
08129c0
docs: Add triage for Copilot comments on PR #140
kevalyq Nov 15, 2025
947b7bb
fix: Address all Copilot review comments and ESLint errors
kevalyq Nov 15, 2025
dec3bc8
fix: Address remaining Copilot review comments with security improvemโ€ฆ
kevalyq Nov 15, 2025
e101e7c
chore: Remove invalid review document causing CI failures
kevalyq Nov 15, 2025
212a4ba
fix: Display validation errors even when no valid shared data exists
kevalyq Nov 15, 2025
36a080e
fix: Address new Copilot comments and improve error handling
kevalyq Nov 15, 2025
57588ec
chore: merge main into feat/share-target-post-file-support
kevalyq Nov 15, 2025
dfea96e
test: improve coverage for Share Target API (80%+ achieved)
kevalyq Nov 15, 2025
2766f9d
chore: ignore coverage directory in ESLint config
kevalyq Nov 15, 2025
59e18a1
fix: resolve TypeScript errors in useShareTarget tests
kevalyq Nov 15, 2025
8bb8fb1
fix: add test timeouts to prevent hanging
kevalyq Nov 15, 2025
968e466
perf: remove verbose reporter from test:run for faster execution
kevalyq Nov 15, 2025
849dcb3
test: attempt to improve Service Worker message handler coverage
kevalyq Nov 15, 2025
c504059
test: add URL cleanup test for ShareTarget component
kevalyq Nov 15, 2025
4ff62b9
refactor: extract Service Worker message handler for better testability
kevalyq Nov 15, 2025
3312f92
test: add validation tests for file initialization edge cases
kevalyq Nov 15, 2025
7f1d745
test: add comprehensive validation tests for file initialization
kevalyq Nov 16, 2025
39dc55e
fix: correct TypeScript types in ShareTarget tests
kevalyq Nov 16, 2025
8e3f6fc
fix: remove unused options parameter in addEventListener mocks
kevalyq Nov 16, 2025
0ca97ea
fix: make handleShareTargetMessage callbacks accept any args for mockโ€ฆ
kevalyq Nov 16, 2025
b237fd9
fix: use any type for mock-compatible callbacks in handleShareTargetMโ€ฆ
kevalyq Nov 16, 2025
56c58c5
fix: add explicit any type annotation for prev parameter
kevalyq Nov 16, 2025
b634445
test: activate Service Worker integration tests with navigator mock
kevalyq Nov 16, 2025
6bc2979
fix: replace any types with proper TypeScript types in ShareTarget.utils
kevalyq Nov 16, 2025
f8035de
fix: make callback types compatible with Vitest mocks
kevalyq Nov 16, 2025
e30f3eb
fix: use any type for callbacks to support Vitest Mocks
kevalyq Nov 16, 2025
9cbf65d
fix: use any type directly for Mock compatibility
kevalyq Nov 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Share Target POST Method & File Sharing** (#101)
- Extended Share Target API to support POST method with file uploads
- Created `ShareTarget` page component with file preview and validation
- Extended `useShareTarget` hook to handle files from sessionStorage
- Implemented custom Service Worker (`sw.ts`) with `injectManifest` strategy
- Service Worker processes FormData, converts images to Base64 for preview
- File validation: type (images, PDFs, docs) and size (max 10MB)
- Support for combined text + file sharing in single share action
- Image preview with thumbnails for shared photos
- File metadata display (name, size, type badge)
- Clear button to remove all shared data
- Updated `PWA_PHASE3_TESTING.md` with comprehensive file sharing test scenarios
- Part of PWA Phase 3 (Epic #64)

- **Code Coverage Integration** (#137)
- Integrated Codecov for automated coverage tracking
- Vitest now generates LCOV and Clover coverage reports
Expand Down
79 changes: 70 additions & 9 deletions PWA_PHASE3_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,49 +92,110 @@ This document describes how to test the new PWA Phase 3 features locally.

### Share Target Components

- PWA Manifest Share Target Config
- URL Parameter Parsing
- PWA Manifest Share Target Config (GET + POST methods)
- URL Parameter Parsing (GET method - text only)
- FormData Parsing (POST method - files + text)
- Service Worker File Processing
- Shared Data Hook (`useShareTarget`)
- File Preview and Validation

### How to Test Share Target

#### Method 1: Text Sharing (GET - Simple)

1. **Install PWA**

```bash
# Chrome: Address bar โ†’ "Install" icon
# Or: DevTools โ†’ Application โ†’ Manifest โ†’ "Install"
```

2. **Share from another app**
- **Option A (Desktop):** Right-click on image โ†’ "Share" โ†’ Select SecPal
2. **Share text from another app**
- **Option A (Desktop):** Right-click on text/link โ†’ "Share" โ†’ Select SecPal
- **Option B (Mobile):** Browser share button โ†’ Select SecPal
- **Option C (Test URL):** Manually open:

```text
http://localhost:5173/share?title=Test&text=Hello&url=https://example.com
```

3. **Test hook integration**
3. **Verify text display**
- App opens at `/share` route
- Title, text, and URL are displayed
- URL parameters are cleaned from address bar

#### Method 2: File Sharing (POST - Advanced)

1. **Install PWA** (same as above)

2. **Share files from another app**
- **Option A (Desktop):** Right-click on image/PDF โ†’ "Share" โ†’ Select SecPal
- **Option B (Mobile):** Gallery/Files app โ†’ Share button โ†’ Select SecPal
- **Option C (Test with multiple files):** Select multiple files โ†’ Share โ†’ SecPal

3. **Verify file handling**
- App opens at `/share` route
- Files are listed with name, size, type badge
- Image files show preview thumbnails
- PDF/DOC files show file icon
- File size is displayed (e.g., "1.2 MB")

4. **Test file validation**
- Try sharing `.exe` or unsupported file โ†’ Error message shown
- Try sharing file >10MB โ†’ Error "File too large. Maximum 10MB"
- Only valid files (images, PDFs, .doc, .docx) are accepted

5. **Check Service Worker processing**

```bash
# Chrome DevTools โ†’ Application โ†’ Service Workers
# Status should be "activated and is running"
# Console โ†’ Check for Service Worker messages:
# "Processing shared files: 2 files"
```

6. **Check sessionStorage**

```bash
# DevTools โ†’ Application โ†’ Storage โ†’ Session Storage
# Key: share-target-files
# Value: JSON array with file metadata + Base64 previews
```

7. **Test combined sharing**
- Share files + text together
- Example: Share image with caption
- Both text and files should appear

8. **Test hook integration**

```tsx
// In a component:
const { sharedData, isSharing, clearSharedData } = useShareTarget();
const { sharedData, clearSharedData } = useShareTarget();

useEffect(() => {
if (sharedData) {
console.log("Shared data:", sharedData);
// Handle: sharedData.title, sharedData.text, sharedData.url
// Handle text: sharedData.title, sharedData.text, sharedData.url
// Handle files: sharedData.files (array of SharedFile objects)
clearSharedData();
}
}, [sharedData]);
```

### Share Target - Success Criteria

- โœ… SecPal appears in OS share menu
- โœ… SecPal appears in OS share menu (both text and file options)
- โœ… **GET method:** Text sharing works (title, text, url)
- โœ… **POST method:** File sharing works (images, PDFs, docs)
- โœ… Files are validated (type + size limits)
- โœ… Image previews are generated (Base64 thumbnails)
- โœ… Service Worker processes FormData correctly
- โœ… App opens with `/share` route
- โœ… `useShareTarget` detects shared data
- โœ… `useShareTarget` detects shared data (text + files)
- โœ… URL is cleaned to `/` after processing
- โœ… sessionStorage stores file metadata
- โœ… Clear button removes all shared data

---

Expand Down
9 changes: 8 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["dist", "src/locales/**/*.js", "src/locales/**/*.mjs"] },
{
ignores: [
"dist",
"coverage",
"src/locales/**/*.js",
"src/locales/**/*.mjs",
],
},
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --cache",
"typecheck": "tsc --noEmit",
"test": "vitest",
"test:run": "vitest run --bail=1 --reporter=verbose",
"test:run": "vitest run --bail=1",
"test:run:all": "vitest run --reporter=verbose",
"test:related": "vitest related --run --bail=1",
"test:ui": "vitest --ui",
Expand Down
21 changes: 19 additions & 2 deletions scripts/preflight.sh
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,27 @@ elif [ -f package-lock.json ] && command -v npm >/dev/null 2>&1; then
npm run --if-present typecheck

# Run only tests related to changed files for faster feedback
# Use timeout to prevent hanging tests (max 5 minutes)
if [ -n "$CHANGED_FILES" ] && echo "$CHANGED_FILES" | grep -qE '\.(ts|tsx|js|jsx)$'; then
npm run --if-present test:related
timeout 300 npm run --if-present test:related || {
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo "โŒ Tests timed out after 5 minutes" >&2
exit 1
else
exit $EXIT_CODE
fi
}
elif [ -z "$CHANGED_FILES" ]; then
npm run --if-present test:run
timeout 300 npm run --if-present test:run || {
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo "โŒ Tests timed out after 5 minutes" >&2
exit 1
else
exit $EXIT_CODE
fi
}
else
echo "No source files changed, skipping tests"
fi
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Link } from "./components/link";
import { OfflineIndicator } from "./components/OfflineIndicator";
import { LanguageSwitcher } from "./components/LanguageSwitcher";
import { SyncStatusIndicator } from "./components/SyncStatusIndicator";
import { ShareTarget } from "./pages/ShareTarget";
import { getApiBaseUrl } from "./config";

function Home() {
Expand Down Expand Up @@ -60,6 +61,7 @@ function App() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/share" element={<ShareTarget />} />
</Routes>
</div>
<OfflineIndicator />
Expand Down
Loading