Frontend Generated Unit Test Reports - bounswe/bounswe2026group4 GitHub Wiki

Frontend Generated Unit Test Reports

Auto-generated: 2026-04-29 18:07 UTC โ€” CI run

๐Ÿ“„ View full HTML report


โœ… All passed  ยท  528 passed  ยท  0 failed  ยท  0 skipped  ยท  528 total  ยท  42.17 s

Full test list
Suite Test Status Duration
ProtectedRoute ProtectedRoute renders children when authenticated โœ… passed 45 ms
ProtectedRoute ProtectedRoute redirects to /login when unauthenticated โœ… passed 9 ms
ProtectedRoute ProtectedRoute redirects to /login with from state preserving the original path โœ… passed 6 ms
useAuth useAuth throws when used outside AuthProvider โœ… passed 15 ms
useAuth useAuth returns context value when used inside provider โœ… passed 3 ms
useFilterState useFilterState returns default values when URL has no params โœ… passed 23 ms
useFilterState useFilterState parses URL params correctly โœ… passed 3 ms
useFilterState useFilterState setFilters updates URL params โœ… passed 6 ms
useFilterState useFilterState setFilters resets page to 1 when non-page params change โœ… passed 3 ms
useFilterState useFilterState setFilters does NOT reset page when only page changes โœ… passed 4 ms
useFilterState useFilterState removeFilter removes a single param and resets page โœ… passed 2 ms
useFilterState useFilterState clearAll removes all params โœ… passed 4 ms
useFilterState useFilterState setFilters removes param when value is empty string โœ… passed 3 ms
useFilterState useFilterState hasActiveFilters is true when any filter param is set โœ… passed 2 ms
AuthContext AuthContext starts unauthenticated with no user โœ… passed 57 ms
AuthContext AuthContext restores user from localStorage on mount โœ… passed 7 ms
AuthContext AuthContext login updates user and authentication state โœ… passed 201 ms
AuthContext AuthContext logout clears auth state and tokens โœ… passed 84 ms
AuthContext AuthContext login stores user in localStorage โœ… passed 49 ms
AuthContext AuthContext logout removes user from localStorage โœ… passed 67 ms
AuthContext AuthContext login failure keeps isAuthenticated false and user null โœ… passed 23 ms
AuthContext AuthContext clears user when auth:logout event is dispatched โœ… passed 29 ms
api api service attaches Authorization header when access token exists โœ… passed 7 ms
api api service does not attach Authorization header when no token exists โœ… passed 1 ms
api api service clears tokens and navigates to /login on 401 when no refresh token โœ… passed 10 ms
api api service does not crash when navigationRef.navigate is null on 401 โœ… passed 5 ms
api api service refreshes token and retries original request on 401 โœ… passed 2 ms
api api service clears tokens and redirects when refresh fails โœ… passed 2 ms
api api service does not attempt refresh for auth endpoints โœ… passed 1 ms
api api service does not retry infinitely if retried request also returns 401 โœ… passed 2 ms
api api service only makes one refresh request for concurrent 401s โœ… passed 2 ms
authService authService login calls API and stores tokens via tokenStore โœ… passed 6 ms
authService authService login does not store tokens on failure โœ… passed 2 ms
authService authService register calls register endpoint and returns data โœ… passed 0 ms
authService authService logout calls API with refresh token and clears tokenStore โœ… passed 0 ms
authService authService logout always resolves even if API call fails โœ… passed 2 ms
authService authService logout clears tokenStore even when API fails โœ… passed 0 ms
followService followService followUser POSTs to /users//follow/ and returns response data โœ… passed 6 ms
followService followService followUser propagates API errors โœ… passed 2 ms
followService followService unfollowUser DELETEs /users//follow/ โœ… passed 0 ms
followService followService unfollowUser propagates API errors โœ… passed 0 ms
followService followService getFollowers GETs /users//followers/ with default pagination โœ… passed 1 ms
followService followService getFollowers passes custom page and pageSize โœ… passed 0 ms
followService followService getFollowers propagates API errors โœ… passed 0 ms
followService followService getFollowing GETs /users//following/ with default pagination โœ… passed 0 ms
followService followService getFollowing passes custom page and pageSize โœ… passed 0 ms
followService followService getFollowing propagates API errors โœ… passed 0 ms
storyService storyService getStories returns paginated response from API โœ… passed 3 ms
storyService storyService getStories calls GET /stories/feed/ with default params when no q is provided โœ… passed 1 ms
storyService storyService getStories passes custom page param to feed API โœ… passed 0 ms
storyService storyService getStories passes custom pageSize to feed API โœ… passed 0 ms
storyService storyService getStories passes yearFrom and yearTo filter params to feed API โœ… passed 0 ms
storyService storyService getStories passes location filter param to feed API โœ… passed 0 ms
storyService storyService getStories calls GET /stories/search/ with q param when q is provided โœ… passed 0 ms
storyService storyService getStories trims whitespace from q before calling search API โœ… passed 0 ms
storyService storyService getStories passes year and location filters to search API when q and filters are combined โœ… passed 0 ms
storyService storyService getStories uses feed API when q is empty string โœ… passed 1 ms
storyService storyService getStories throws on API error โœ… passed 2 ms
storyService storyService getMapStories calls GET /stories/map/ with no params by default โœ… passed 0 ms
storyService storyService getMapStories returns the GeoJSON FeatureCollection from the map endpoint with totalCount โœ… passed 0 ms
storyService storyService getMapStories passes yearFrom, yearTo and location filter params to map API โœ… passed 0 ms
storyService storyService getMapStories calls search API when q is provided and adapts results into a FeatureCollection โœ… passed 1 ms
storyService storyService getMapStories passes year and location filters to search API when q and filters are combined โœ… passed 0 ms
storyService storyService getMapStories throws on API error โœ… passed 0 ms
storyService storyService deleteStory calls api.delete with correct URL โœ… passed 0 ms
storyService storyService deleteStory throws on API error โœ… passed 0 ms
tokenStore tokenStore stores and retrieves access token โœ… passed 2 ms
tokenStore tokenStore stores and retrieves refresh token โœ… passed 0 ms
tokenStore tokenStore clear() resets both tokens to null โœ… passed 0 ms
tokenStore tokenStore clear() dispatches auth:logout event on window โœ… passed 1 ms
tokenStore tokenStore setAccessToken persists to localStorage โœ… passed 0 ms
tokenStore tokenStore setRefreshToken persists to localStorage โœ… passed 0 ms
tokenStore tokenStore clear() removes tokens and user from localStorage โœ… passed 0 ms
tokenStore tokenStore reads tokens from localStorage on module load โœ… passed 0 ms
userService userService getPublicProfile calls GET /users// and returns data โœ… passed 4 ms
userService userService getPublicProfile propagates API errors โœ… passed 2 ms
userService userService getProfile (alias) is the same function as getPublicProfile โœ… passed 0 ms
userService userService getOwnProfile calls GET /users/me/ and returns the unwrapped user object โœ… passed 0 ms
userService userService updateProfile sends PATCH /users/me/ with only user fields when no profile fields given โœ… passed 0 ms
userService userService updateProfile nests profile fields under 'profile' key โœ… passed 0 ms
userService userService updateProfile omits 'profile' key when profileFields is empty โœ… passed 1 ms
userService userService updateProfile returns response data โœ… passed 0 ms
userService userService updateProfile propagates API errors โœ… passed 0 ms
userService userService uploadProfilePhoto sends POST /users/me/photo/ as multipart with correct field name โœ… passed 1 ms
userService userService uploadProfilePhoto propagates API errors โœ… passed 0 ms
userService userService removeProfilePhoto sends DELETE /users/me/photo/ โœ… passed 0 ms
userService userService removeProfilePhoto propagates API errors โœ… passed 0 ms
FeedPage FeedPage shows loading skeletons while fetching โœ… passed 80 ms
FeedPage FeedPage renders story cards after successful fetch โœ… passed 67 ms
FeedPage FeedPage shows empty state when results are empty โœ… passed 19 ms
FeedPage FeedPage shows 'no results' empty state when filters are active and results are empty โœ… passed 32 ms
FeedPage FeedPage shows error state when API throws โœ… passed 177 ms
FeedPage FeedPage retry button calls service again after error โœ… passed 133 ms
FeedPage FeedPage shows pagination controls when stories are present โœ… passed 84 ms
FeedPage FeedPage previous button is disabled on page 1 โœ… passed 118 ms
FeedPage FeedPage next button is disabled when next is null โœ… passed 76 ms
FeedPage FeedPage next button is enabled when next is not null โœ… passed 66 ms
FeedPage FeedPage clicking next button fetches page 2 โœ… passed 92 ms
FeedPage FeedPage clicking previous button fetches previous page โœ… passed 195 ms
FeedPage FeedPage displays current page and total pages โœ… passed 56 ms
FeedPage FeedPage shows 'Most Recent' sort button โœ… passed 30 ms
FeedPage FeedPage renders the page heading โœ… passed 26 ms
FeedPage FeedPage each story card is a link to /stories/:id โœ… passed 34 ms
FeedPage FeedPage renders the search bar โœ… passed 38 ms
FeedPage FeedPage calls getStories with q param from URL โœ… passed 30 ms
FeedPage FeedPage calls getStories with year filter params from URL โœ… passed 25 ms
FeedPage FeedPage shows result count when filters are active and stories exist โœ… passed 34 ms
LoginPage LoginPage renders login form correctly โœ… passed 246 ms
LoginPage LoginPage shows validation error for empty email โœ… passed 86 ms
LoginPage LoginPage shows validation error for empty password โœ… passed 196 ms
LoginPage LoginPage does not submit when email format is invalid โœ… passed 197 ms
LoginPage LoginPage submits form with valid credentials via auth context โœ… passed 228 ms
LoginPage LoginPage shows loading state during submission โœ… passed 228 ms
LoginPage LoginPage shows API error message on login failure โœ… passed 196 ms
LoginPage LoginPage toggles password visibility โœ… passed 39 ms
LoginPage LoginPage navigates to home on successful login โœ… passed 239 ms
LoginPage LoginPage displays API error with role='alert' for accessibility โœ… passed 216 ms
LoginPage LoginPage navigates to redirect path from location state after login โœ… passed 208 ms
LoginPage LoginPage has link to registration page โœ… passed 23 ms
LoginPage LoginPage shows contextual message when redirected from submit-story โœ… passed 9 ms
LoginPage LoginPage navigates to /submit-story after login when redirected from submit-story โœ… passed 265 ms
LoginPage LoginPage shows success toast on successful login โœ… passed 197 ms
LoginPage LoginPage shows error.response.data.detail when message is absent โœ… passed 203 ms
LoginPage LoginPage shows hardcoded fallback when no response data is available โœ… passed 236 ms
LoginPage LoginPage redirects away from login page when already authenticated โœ… passed 5 ms
MapPage MapPage renders the map container โœ… passed 71 ms
MapPage MapPage shows loading state while fetching โœ… passed 27 ms
MapPage MapPage renders markers after successful fetch โœ… passed 38 ms
MapPage MapPage shows error alert when API fails โœ… passed 126 ms
MapPage MapPage retry button refetches after error โœ… passed 131 ms
MapPage MapPage shows no markers when API returns an empty FeatureCollection โœ… passed 8 ms
MapPage MapPage search status indicator shows story count when filters are active and results exist โœ… passed 21 ms
MapPage MapPage search status indicator shows singular 'story' when exactly one result exists โœ… passed 16 ms
MapPage MapPage search status indicator shows empty message when filters are active but no results exist โœ… passed 18 ms
MapPage MapPage search status indicator shows cap notice when totalCount exceeds 100 with q filter โœ… passed 38 ms
MapPage MapPage search status indicator does not show indicator while loading โœ… passed 11 ms
MapPage MapPage search status indicator does not show indicator when no filters are active โœ… passed 13 ms
NotFoundPage NotFoundPage renders the 404 heading โœ… passed 198 ms
NotFoundPage NotFoundPage renders a friendly message โœ… passed 45 ms
NotFoundPage NotFoundPage renders a description paragraph โœ… passed 23 ms
NotFoundPage NotFoundPage renders a link back to home โœ… passed 23 ms
NotFoundPage NotFoundPage navigates to home when the link is clicked โœ… passed 46 ms
ProfileCompletionPage ProfileCompletionPage renders all form fields โœ… passed 357 ms
ProfileCompletionPage ProfileCompletionPage renders all privacy toggles โœ… passed 63 ms
ProfileCompletionPage ProfileCompletionPage shows the page title and description โœ… passed 26 ms
ProfileCompletionPage ProfileCompletionPage shows errors when required fields are empty on submit โœ… passed 140 ms
ProfileCompletionPage ProfileCompletionPage shows error when name is empty โœ… passed 244 ms
ProfileCompletionPage ProfileCompletionPage shows error when surname is empty โœ… passed 167 ms
ProfileCompletionPage ProfileCompletionPage shows error when location exceeds 255 characters โœ… passed 2.04 s
ProfileCompletionPage ProfileCompletionPage accepts a valid birth date โœ… passed 237 ms
ProfileCompletionPage ProfileCompletionPage shows error when a non-image file is uploaded โœ… passed 43 ms
ProfileCompletionPage ProfileCompletionPage accepts a valid image file upload โœ… passed 33 ms
ProfileCompletionPage ProfileCompletionPage shows photo preview after valid image upload โœ… passed 35 ms
ProfileCompletionPage ProfileCompletionPage remove photo button is not shown before a photo is selected โœ… passed 46 ms
ProfileCompletionPage ProfileCompletionPage remove photo button appears after a photo is selected โœ… passed 52 ms
ProfileCompletionPage ProfileCompletionPage clicking remove photo clears the preview, filename, and remove button โœ… passed 91 ms
ProfileCompletionPage ProfileCompletionPage submits without a photo after removing the selected file โœ… passed 276 ms
ProfileCompletionPage ProfileCompletionPage calls updateCurrentUser with required fields only โœ… passed 210 ms
ProfileCompletionPage ProfileCompletionPage navigates to home after successful submission with no 'from' state โœ… passed 195 ms
ProfileCompletionPage ProfileCompletionPage navigates to original destination after successful submission when 'from' state exists โœ… passed 203 ms
ProfileCompletionPage ProfileCompletionPage shows success toast on profile completion โœ… passed 179 ms
ProfileCompletionPage ProfileCompletionPage includes optional fields when provided โœ… passed 396 ms
ProfileCompletionPage ProfileCompletionPage includes profile photo in payload when a valid image is uploaded โœ… passed 156 ms
ProfileCompletionPage ProfileCompletionPage sends is_name_public in profile payload โœ… passed 202 ms
ProfileCompletionPage ProfileCompletionPage sends is_username_public in userFields payload โœ… passed 183 ms
ProfileCompletionPage ProfileCompletionPage sends is_location_public in profile payload when toggled off โœ… passed 239 ms
ProfileCompletionPage ProfileCompletionPage shows generic API error on failure โœ… passed 147 ms
ProfileCompletionPage ProfileCompletionPage shows backend field errors for profile fields โœ… passed 126 ms
ProfileCompletionPage ProfileCompletionPage shows loading state and disables button during submission โœ… passed 219 ms
ProfileCompletionPage ProfileCompletionPage clears name error when user starts typing โœ… passed 74 ms
ProfileCompletionPage ProfileCompletionPage clears surname error when user starts typing โœ… passed 86 ms
ProfileCompletionPage ProfileCompletionPage skip link points to home when no 'from' state โœ… passed 21 ms
ProfileCompletionPage ProfileCompletionPage skip link points to original destination when 'from' state exists โœ… passed 22 ms
ProfilePage ProfilePage shows loading skeleton while fetching โœ… passed 68 ms
ProfilePage ProfilePage displays user info after successful fetch โœ… passed 88 ms
ProfilePage ProfilePage shows story listing coming soon message โœ… passed 19 ms
ProfilePage ProfilePage shows error state on API failure โœ… passed 157 ms
ProfilePage ProfilePage retry button re-fetches data after error โœ… passed 81 ms
ProfilePage ProfilePage displays story count matching published_story_count โœ… passed 18 ms
ProfilePage ProfilePage displays singular 'story' when published_story_count is 1 โœ… passed 26 ms
ProfilePage ProfilePage hides bio when not present โœ… passed 23 ms
ProfilePage ProfilePage hides total_points when zero โœ… passed 25 ms
ProfilePage ProfilePage follow integration does NOT render the follow button on the user's own profile โœ… passed 36 ms
ProfilePage ProfilePage follow integration renders the follow button on someone else's profile with initial state โœ… passed 21 ms
ProfilePage ProfilePage follow integration displays follower and following counts from the profile payload โœ… passed 87 ms
ProfilePage ProfilePage follow integration uses singular 'follower' when count is 1 โœ… passed 71 ms
ProfilePage ProfilePage follow integration opens the followers sheet when the followers count is clicked โœ… passed 92 ms
ProfilePage ProfilePage follow integration opens the following sheet when the following count is clicked โœ… passed 95 ms
ProfilePage ProfilePage follow integration optimistically updates the follower count when follow toggles โœ… passed 80 ms
ProfilePage ProfilePage follow integration defaults follower/following counts to zero when missing from payload โœ… passed 69 ms
ProfilePage ProfilePage edit profile shows Edit Profile button on own profile โœ… passed 55 ms
ProfilePage ProfilePage edit profile does NOT show Edit Profile button on another user's profile โœ… passed 49 ms
ProfilePage ProfilePage edit profile renders EditProfileForm when Edit Profile is clicked โœ… passed 119 ms
ProfilePage ProfilePage edit profile hides EditProfileForm, re-fetches public and own profile when onSave is called โœ… passed 138 ms
ProfilePage ProfilePage edit profile hides EditProfileForm without re-fetching when onCancel is called โœ… passed 135 ms
ProfilePage ProfilePage public profile fields renders profile photo when profile_photo is present โœ… passed 18 ms
ProfilePage ProfilePage public profile fields renders first and last name when present โœ… passed 24 ms
ProfilePage ProfilePage public profile fields renders full birth date when birth_date is present โœ… passed 41 ms
ProfilePage ProfilePage public profile fields falls back to birth_year when only birth_year is present โœ… passed 15 ms
ProfilePage ProfilePage public profile fields does not render birth info when both absent โœ… passed 20 ms
ProfilePage ProfilePage own profile โ€” birthday fallback when ownProfileData.birth_date is null falls back to profile.birth_year when own profile has no birth_date set but public โœ… passed 27 ms
ProfilePage ProfilePage own profile โ€” private field visibility shows private location on own profile โœ… passed 42 ms
ProfilePage ProfilePage own profile โ€” private field visibility shows Private badge next to private location โœ… passed 49 ms
ProfilePage ProfilePage own profile โ€” private field visibility shows private bio on own profile โœ… passed 31 ms
ProfilePage ProfilePage own profile โ€” private field visibility shows private birth date on own profile โœ… passed 34 ms
ProfilePage ProfilePage own profile โ€” private field visibility shows private name on own profile with Private badge โœ… passed 28 ms
ProfilePage ProfilePage own profile โ€” private field visibility does NOT show private fields on another user's profile โœ… passed 22 ms
RegisterPage RegisterPage renders registration form with all required fields โœ… passed 335 ms
RegisterPage RegisterPage shows error when username is empty โœ… passed 567 ms
RegisterPage RegisterPage shows error when email is empty โœ… passed 379 ms
RegisterPage RegisterPage shows error for invalid email format โœ… passed 386 ms
RegisterPage RegisterPage shows error when password is empty โœ… passed 342 ms
RegisterPage RegisterPage shows error when password is too short โœ… passed 366 ms
RegisterPage RegisterPage shows error when password lacks uppercase letter โœ… passed 429 ms
RegisterPage RegisterPage shows error when password lacks lowercase letter โœ… passed 375 ms
RegisterPage RegisterPage shows error when password lacks a number โœ… passed 439 ms
RegisterPage RegisterPage shows error when confirm password is empty โœ… passed 379 ms
RegisterPage RegisterPage shows error when passwords do not match โœ… passed 472 ms
RegisterPage RegisterPage calls register with correct arguments on valid submission โœ… passed 485 ms
RegisterPage RegisterPage calls login with email and password after successful registration โœ… passed 496 ms
RegisterPage RegisterPage navigates to /complete-profile after successful registration and auto-login โœ… passed 458 ms
RegisterPage RegisterPage passes the original destination in state when navigating to /complete-profile โœ… passed 415 ms
RegisterPage RegisterPage preserves URL search params in state when navigating to /complete-profile โœ… passed 405 ms
RegisterPage RegisterPage shows welcome toast on successful registration and auto-login โœ… passed 376 ms
RegisterPage RegisterPage navigates to /login with from state when auto-login fails โœ… passed 396 ms
RegisterPage RegisterPage shows a sign-in guidance toast when auto-login fails โœ… passed 401 ms
RegisterPage RegisterPage shows loading state and disables button during submission โœ… passed 346 ms
RegisterPage RegisterPage shows generic API error on failure โœ… passed 400 ms
RegisterPage RegisterPage shows API error with role='alert' for accessibility โœ… passed 373 ms
RegisterPage RegisterPage displays backend field error for duplicate email โœ… passed 421 ms
RegisterPage RegisterPage displays backend field error for duplicate username โœ… passed 369 ms
RegisterPage RegisterPage clears field error when user starts typing in that field โœ… passed 71 ms
RegisterPage RegisterPage toggles password visibility โœ… passed 47 ms
RegisterPage RegisterPage toggles confirm password visibility โœ… passed 42 ms
RegisterPage RegisterPage has a link to the login page โœ… passed 17 ms
StoryDetailPage StoryDetailPage shows loading skeleton while fetching โœ… passed 84 ms
StoryDetailPage StoryDetailPage renders story title after successful fetch โœ… passed 255 ms
StoryDetailPage StoryDetailPage renders location name โœ… passed 34 ms
StoryDetailPage StoryDetailPage renders formatted time period โœ… passed 35 ms
StoryDetailPage StoryDetailPage renders submitted date with 'Date added' label โœ… passed 30 ms
StoryDetailPage StoryDetailPage renders each narrative paragraph separately โœ… passed 27 ms
StoryDetailPage StoryDetailPage shows not-found state on 404 response โœ… passed 18 ms
StoryDetailPage StoryDetailPage shows error state on non-404 API failure โœ… passed 35 ms
StoryDetailPage StoryDetailPage shows API error detail message when provided โœ… passed 22 ms
StoryDetailPage StoryDetailPage retry button re-fetches the story after error โœ… passed 140 ms
StoryDetailPage StoryDetailPage stories link is present in loaded state โœ… passed 85 ms
StoryDetailPage StoryDetailPage stories link is present in not-found state โœ… passed 33 ms
StoryDetailPage StoryDetailPage stories link is present in error state โœ… passed 38 ms
StoryDetailPage StoryDetailPage renders contributor name as a link to their profile โœ… passed 38 ms
StoryDetailPage StoryDetailPage omits contributor name when absent โœ… passed 48 ms
StoryDetailPage StoryDetailPage renders images from media_items when present โœ… passed 44 ms
StoryDetailPage StoryDetailPage does not render image section when media_items are absent โœ… passed 43 ms
StoryDetailPage StoryDetailPage only renders image media_type items, not audio or video โœ… passed 54 ms
StoryDetailPage StoryDetailPage renders map when coordinates are present โœ… passed 17 ms
StoryDetailPage StoryDetailPage does not render map when coordinates are absent โœ… passed 29 ms
StoryDetailPage StoryDetailPage omits location when location_name is absent โœ… passed 34 ms
StoryDetailPage StoryDetailPage omits date when submitted_at is absent โœ… passed 27 ms
StoryDetailPage StoryDetailPage calls getStoryById with the correct id from the URL โœ… passed 17 ms
StoryDetailPage StoryDetailPage renders decade time period correctly โœ… passed 28 ms
StoryDetailPage StoryDetailPage renders LikeButton with story like data โœ… passed 15 ms
StoryDetailPage StoryDetailPage renders comment count from CommentSection next to like button โœ… passed 24 ms
StoryDetailPage StoryDetailPage renders CommentSection with story id โœ… passed 17 ms
StoryDetailPage StoryDetailPage renders year range time period correctly โœ… passed 22 ms
StoryDetailPage StoryDetailPage back button navigates to map when navigated from map view โœ… passed 50 ms
StoryDetailPage StoryDetailPage back button navigates to feed when no from state โœ… passed 68 ms
StoryDetailPage StoryDetailPage delete story does not show delete button when user is not authenticated โœ… passed 24 ms
StoryDetailPage StoryDetailPage delete story does not show delete button when user is not the owner or admin โœ… passed 35 ms
StoryDetailPage StoryDetailPage delete story shows delete button when user is the story owner โœ… passed 55 ms
StoryDetailPage StoryDetailPage delete story shows delete button when user is admin โœ… passed 40 ms
StoryDetailPage StoryDetailPage delete story does not delete when confirmation is cancelled โœ… passed 219 ms
StoryDetailPage StoryDetailPage delete story deletes story and navigates to feed on success โœ… passed 137 ms
StoryDetailPage StoryDetailPage delete story shows error toast on delete failure โœ… passed 111 ms
SubmitStoryPage SubmitStoryPage renders all form fields โœ… passed 282 ms
SubmitStoryPage SubmitStoryPage shows validation errors when submitting empty form โœ… passed 113 ms
SubmitStoryPage SubmitStoryPage shows year input for exact_year time type โœ… passed 21 ms
SubmitStoryPage SubmitStoryPage shows year range inputs when year_range is selected โœ… passed 65 ms
SubmitStoryPage SubmitStoryPage validates year range - start must be before end โœ… passed 599 ms
SubmitStoryPage SubmitStoryPage validates year range - both years required โœ… passed 92 ms
SubmitStoryPage SubmitStoryPage rejects image files that are not JPG/PNG โœ… passed 24 ms
SubmitStoryPage SubmitStoryPage rejects images larger than 2MB โœ… passed 18 ms
SubmitStoryPage SubmitStoryPage shows image preview for valid image โœ… passed 45 ms
SubmitStoryPage SubmitStoryPage submits form successfully and navigates โœ… passed 384 ms
SubmitStoryPage SubmitStoryPage shows API error message on submission failure โœ… passed 396 ms
SubmitStoryPage SubmitStoryPage renders tag checkboxes โœ… passed 27 ms
SubmitStoryPage SubmitStoryPage uploads image after story creation when image is selected โœ… passed 410 ms
SubmitStoryPage SubmitStoryPage navigates and shows error toast when image upload fails after story creation โœ… passed 359 ms
SubmitStoryPage SubmitStoryPage does not call uploadStoryImage when no image is selected โœ… passed 328 ms
SubmitStoryPage SubmitStoryPage limits tag selection to 3 โœ… passed 117 ms
AppLayout AppLayout renders navbar with public links โœ… passed 89 ms
AppLayout AppLayout shows Login and Register buttons when unauthenticated โœ… passed 21 ms
AppLayout AppLayout shows Submit Story link for unauthenticated users โœ… passed 14 ms
AppLayout AppLayout shows username linking to profile, Logout, and Submit Story when authenticated โœ… passed 246 ms
AppLayout AppLayout highlights active route โœ… passed 13 ms
AppLayout AppLayout calls logout and navigates to / on logout click โœ… passed 75 ms
AppLayout AppLayout renders page content via Outlet โœ… passed 9 ms
AppLayout AppLayout Map link carries current search params when on the Feed page โœ… passed 58 ms
AppLayout AppLayout Feed link carries current search params when on the Map page โœ… passed 37 ms
AppLayout AppLayout Map and Feed links use bare paths when on a non-filter page โœ… passed 67 ms
AppLayout AppLayout Map and Feed links use bare paths when there are no active filters โœ… passed 25 ms
AppLayout AppLayout Map link is still highlighted when filters are active on /map โœ… passed 10 ms
AppLayout AppLayout Feed link is still highlighted when filters are active on / โœ… passed 14 ms
AppLayout AppLayout renders mobile hamburger button โœ… passed 15 ms
AppLayout AppLayout mobile drawer Login button navigates to /login โœ… passed 182 ms
AppLayout AppLayout mobile drawer Register button navigates to /register โœ… passed 157 ms
MapPicker MapPicker renders the map container โœ… passed 30 ms
MapPicker MapPicker does not show marker when value is null โœ… passed 3 ms
MapPicker MapPicker shows marker when value is provided โœ… passed 4 ms
MapPicker MapPicker displays coordinates when value is provided โœ… passed 7 ms
MapPicker MapPicker shows instruction text when no location selected โœ… passed 3 ms
MapPicker MapPicker calls onChange when map is clicked โœ… passed 3 ms
CommentSection CommentSection loading and error states shows loading indicator while fetching โœ… passed 52 ms
CommentSection CommentSection loading and error states shows error message when fetch fails โœ… passed 179 ms
CommentSection CommentSection comment list rendering shows empty state when no comments โœ… passed 11 ms
CommentSection CommentSection comment list rendering renders a list of comments with author and text โœ… passed 34 ms
CommentSection CommentSection comment list rendering displays comments in reverse chronological order (most recent first) โœ… passed 52 ms
CommentSection CommentSection comment list rendering shows the comment count in the heading โœ… passed 70 ms
CommentSection CommentSection comment list rendering renders 'Anonymous' for comments without an author username โœ… passed 10 ms
CommentSection CommentSection unauthenticated user shows a login prompt instead of the comment form โœ… passed 26 ms
CommentSection CommentSection unauthenticated user login prompt links to /login โœ… passed 29 ms
CommentSection CommentSection authenticated user shows the comment input form โœ… passed 56 ms
CommentSection CommentSection authenticated user submits a new comment and shows it at the top โœ… passed 184 ms
CommentSection CommentSection authenticated user disables submit button and shows loading state during submission โœ… passed 94 ms
CommentSection CommentSection authenticated user clears the input after successful submission โœ… passed 93 ms
CommentSection CommentSection authenticated user shows an error message when comment submission fails โœ… passed 95 ms
CommentSection CommentSection authenticated user disables submit when text is empty โœ… passed 13 ms
CommentSection CommentSection authenticated user shows delete button only on own comments โœ… passed 23 ms
CommentSection CommentSection authenticated user clicking delete shows inline confirmation with Delete and Cancel buttons โœ… passed 67 ms
CommentSection CommentSection authenticated user hides the trash icon while inline confirmation is open โœ… passed 65 ms
CommentSection CommentSection authenticated user deletes own comment after inline confirmation โœ… passed 85 ms
CommentSection CommentSection authenticated user cancelling inline confirmation keeps the comment and restores the trash icon โœ… passed 99 ms
CommentSection CommentSection authenticated user shows an error message when delete fails โœ… passed 81 ms
CommentSection CommentSection onUserCommentedChange callback calls onUserCommentedChange(false) when the current user has no comments โœ… passed 4 ms
CommentSection CommentSection onUserCommentedChange callback calls onUserCommentedChange(true) when the current user has a comment โœ… passed 54 ms
CommentSection CommentSection onUserCommentedChange callback calls onUserCommentedChange(false) when user is unauthenticated โœ… passed 5 ms
CommentSection CommentSection onUserCommentedChange callback calls onUserCommentedChange(true) after the user posts a new comment โœ… passed 109 ms
LikeButton LikeButton unauthenticated user displays the like count โœ… passed 80 ms
LikeButton LikeButton unauthenticated user shows a login prompt instead of a toggle button โœ… passed 181 ms
LikeButton LikeButton unauthenticated user login prompt links to /login โœ… passed 25 ms
LikeButton LikeButton authenticated user renders a like button with the current count โœ… passed 49 ms
LikeButton LikeButton authenticated user shows 'Unlike story' label when already liked โœ… passed 17 ms
LikeButton LikeButton authenticated user optimistically increments count and calls likeStory on click โœ… passed 61 ms
LikeButton LikeButton authenticated user optimistically decrements count and calls unlikeStory when unliking โœ… passed 27 ms
LikeButton LikeButton authenticated user reverts like on API error โœ… passed 55 ms
LikeButton LikeButton authenticated user reverts unlike on API error โœ… passed 46 ms
MapView MapView renders the map container โœ… passed 35 ms
MapView MapView renders a marker for each feature in the FeatureCollection โœ… passed 18 ms
MapView MapView passes the FeatureCollection as-is to the GeoJSON layer โœ… passed 6 ms
MapView MapView does not render a GeoJSON layer when the FeatureCollection is empty โœ… passed 4 ms
MapView MapView handles a missing featureCollection prop without crashing โœ… passed 4 ms
MapView MapView shows loading overlay when loading is true โœ… passed 129 ms
MapView MapView hides loading overlay when loading is false โœ… passed 4 ms
MapView MapView exposes the feature title in the marker element โœ… passed 6 ms
MapView onEachFeature binds a popup whose HTML contains title, location, time period, and a Read more link โœ… passed 2 ms
MapView onEachFeature omits the location line when location_name is missing โœ… passed 0 ms
MapView StoryLinkInterceptor intercepts clicks on /stories/ anchors inside the map and navigates via react-router โœ… passed 97 ms
StoryPopup StoryPopup renders title, location, and time period โœ… passed 30 ms
StoryPopup StoryPopup handles missing location_name โœ… passed 4 ms
StoryPopup StoryPopup 'Read more' links to the correct story URL โœ… passed 4 ms
EditProfileForm EditProfileForm field pre-population pre-populates username โœ… passed 128 ms
EditProfileForm EditProfileForm field pre-population pre-populates first name and last name from own profile โœ… passed 17 ms
EditProfileForm EditProfileForm field pre-population pre-populates location and bio โœ… passed 24 ms
EditProfileForm EditProfileForm field pre-population pre-populates birth date โœ… passed 9 ms
EditProfileForm EditProfileForm field pre-population reflects privacy flags from profile โ€” birth date switch is off (Private) โœ… passed 185 ms
EditProfileForm EditProfileForm field pre-population handles missing profile gracefully with empty defaults โœ… passed 26 ms
EditProfileForm EditProfileForm visibility toggles location toggle is on (Public) when is_location_public is true โœ… passed 59 ms
EditProfileForm EditProfileForm visibility toggles toggles location from Public to Private on click โœ… passed 127 ms
EditProfileForm EditProfileForm visibility toggles toggles name visibility and sends updated value on save โœ… passed 139 ms
EditProfileForm EditProfileForm photo upload shows error for unsupported file type โœ… passed 32 ms
EditProfileForm EditProfileForm photo upload shows error when file exceeds 2 MB โœ… passed 21 ms
EditProfileForm EditProfileForm photo upload shows preview image when a valid file is selected โœ… passed 18 ms
EditProfileForm EditProfileForm photo upload clears preview when Remove photo is clicked โœ… passed 61 ms
EditProfileForm EditProfileForm bio displays character counter โœ… passed 9 ms
EditProfileForm EditProfileForm bio updates counter as user types โœ… passed 60 ms
EditProfileForm EditProfileForm bio shows validation error on submit when bio exceeds 500 chars โœ… passed 64 ms
EditProfileForm EditProfileForm birth date validation shows error when birth date is in the future โœ… passed 65 ms
EditProfileForm EditProfileForm birth date validation shows error when birth date is before 1900 โœ… passed 57 ms
EditProfileForm EditProfileForm cancel calls onCancel when Cancel button is clicked โœ… passed 50 ms
EditProfileForm EditProfileForm username validation shows error and blocks save when username is empty โœ… passed 71 ms
EditProfileForm EditProfileForm username validation clears username error when user starts typing โœ… passed 90 ms
EditProfileForm EditProfileForm save flow sends all profile fields to updateProfile โœ… passed 51 ms
EditProfileForm EditProfileForm save flow calls uploadProfilePhoto before updateProfile when new photo selected โœ… passed 59 ms
EditProfileForm EditProfileForm save flow calls removeProfilePhoto before updateProfile when photo removed โœ… passed 105 ms
EditProfileForm EditProfileForm save flow does not call uploadProfilePhoto or removeProfilePhoto when photo unchanged โœ… passed 49 ms
EditProfileForm EditProfileForm save flow shows success toast and calls onSave after successful save โœ… passed 56 ms
EditProfileForm EditProfileForm save flow shows error toast when updateProfile fails โœ… passed 47 ms
EditProfileForm EditProfileForm save flow disables Cancel during save โœ… passed 81 ms
FollowButton FollowButton unauthenticated visitor renders a login link instead of a toggle button โœ… passed 238 ms
FollowButton FollowButton unauthenticated visitor does not call follow APIs โœ… passed 50 ms
FollowButton FollowButton authenticated user, not yet following renders 'Follow' label โœ… passed 35 ms
FollowButton FollowButton authenticated user, not yet following optimistically switches to 'Following' on click and calls followUser โœ… passed 63 ms
FollowButton FollowButton authenticated user, not yet following invokes onChange with the new following state โœ… passed 26 ms
FollowButton FollowButton authenticated user, not yet following reverts to 'Follow' and calls onChange(false) when followUser rejects โœ… passed 41 ms
FollowButton FollowButton authenticated user, already following renders 'Following' label โœ… passed 11 ms
FollowButton FollowButton authenticated user, already following optimistically switches to 'Follow' on click and calls unfollowUser โœ… passed 34 ms
FollowButton FollowButton authenticated user, already following reverts to 'Following' when unfollowUser rejects โœ… passed 31 ms
FollowListSheet FollowListSheet loads followers on open and renders them โœ… passed 432 ms
FollowListSheet FollowListSheet appends the second page when 'Load more' is clicked โœ… passed 135 ms
FollowListSheet FollowListSheet shows an ErrorState with retry when the initial load fails โœ… passed 70 ms
FollowListSheet FollowListSheet shows an EmptyState when there are no followers โœ… passed 53 ms
FollowListSheet FollowListSheet closes the sheet when a user link is clicked โœ… passed 101 ms
FollowListSheet FollowListSheet uses the following endpoint in following mode and renders its empty copy โœ… passed 47 ms
FollowListSheet FollowListSheet treats malformed payloads as an empty list โœ… passed 79 ms
StoryDetailMap StoryDetailMap renders the map container โœ… passed 38 ms
StoryDetailMap StoryDetailMap centers the map on the provided coordinates โœ… passed 5 ms
StoryDetailMap StoryDetailMap renders a marker at the provided coordinates โœ… passed 3 ms
StoryDetailMap StoryDetailMap uses zoom level 14 โœ… passed 6 ms
StructuredData StructuredData renders a <script type='application/ld+json'> tag โœ… passed 39 ms
StructuredData StructuredData returns null when neither story nor user is provided โœ… passed 2 ms
StructuredData StructuredData escapes </script> sequences in user-supplied content โœ… passed 5 ms
StructuredData StructuredData story mapping includes author.name when contributor_name is present โœ… passed 5 ms
StructuredData StructuredData story mapping omits author entirely when contributor_name is null (anonymous story) โœ… passed 3 ms
StructuredData StructuredData story mapping does not emit image/audio/video keys when there are no media items โœ… passed 4 ms
StructuredData StructuredData story mapping does not emit keywords when tags are absent or empty โœ… passed 20 ms
StructuredData StructuredData story mapping emits keywords when tags are provided โœ… passed 4 ms
StructuredData StructuredData story mapping splits mixed media items into image/audio/video arrays โœ… passed 9 ms
StructuredData StructuredData story mapping temporal coverage derivation exact_year yields the year as a string โœ… passed 18 ms
StructuredData StructuredData story mapping temporal coverage derivation approximate_year yields the year as a string โœ… passed 10 ms
StructuredData StructuredData story mapping temporal coverage derivation decade yields start/end of the decade โœ… passed 3 ms
StructuredData StructuredData story mapping temporal coverage derivation year_range yields start/end โœ… passed 2 ms
StructuredData StructuredData story mapping temporal coverage derivation prefers temporal_coverage_iso8601 from the API over derivation โœ… passed 2 ms
StructuredData StructuredData user mapping emits Person with name and the canonical @id โœ… passed 3 ms
StructuredData StructuredData user mapping omits name when username is null (privacy) โœ… passed 2 ms
ActiveFilters ActiveFilters renders nothing when no filters are active โœ… passed 20 ms
ActiveFilters ActiveFilters shows a chip for the search query โœ… passed 59 ms
ActiveFilters ActiveFilters shows a combined year range chip when both yearFrom and yearTo are set โœ… passed 8 ms
ActiveFilters ActiveFilters shows 'From N' chip when only yearFrom is set โœ… passed 5 ms
ActiveFilters ActiveFilters shows 'To N' chip when only yearTo is set โœ… passed 6 ms
ActiveFilters ActiveFilters shows a location chip โœ… passed 6 ms
ActiveFilters ActiveFilters shows multiple chips simultaneously โœ… passed 21 ms
ActiveFilters ActiveFilters shows a Clear all button when any filter is active โœ… passed 153 ms
ActiveFilters ActiveFilters calls onRemove('q') when search chip X is clicked โœ… passed 70 ms
ActiveFilters ActiveFilters calls onRemove('year_range') when combined year chip X is clicked โœ… passed 48 ms
ActiveFilters ActiveFilters calls onRemove('year_from') when From chip X is clicked โœ… passed 24 ms
ActiveFilters ActiveFilters calls onRemove('location') when location chip X is clicked โœ… passed 58 ms
ActiveFilters ActiveFilters calls onClearAll when Clear all button is clicked โœ… passed 38 ms
FilterPanel FilterPanel renders a Filters toggle button โœ… passed 196 ms
FilterPanel FilterPanel shows active filter count badge when activeCount > 0 โœ… passed 22 ms
FilterPanel FilterPanel panel is initially hidden โœ… passed 9 ms
FilterPanel FilterPanel opens the panel when toggle button is clicked โœ… passed 75 ms
FilterPanel FilterPanel closes the panel after clicking Apply โœ… passed 90 ms
FilterPanel FilterPanel calls onApply with entered values when Apply is clicked โœ… passed 326 ms
FilterPanel FilterPanel shows validation error when yearFrom > yearTo โœ… passed 214 ms
FilterPanel FilterPanel resets form and calls onApply with empty values when Reset filters is clicked โœ… passed 58 ms
FilterPanel FilterPanel initialises form fields from props on mount โœ… passed 32 ms
FilterPanel FilterPanel year fields are empty on first open (placeholder visible) โœ… passed 25 ms
FilterPanel FilterPanel both inputs have min=1000 and max=2030 โœ… passed 22 ms
FilterPanel FilterPanel ArrowUp on empty From year sets it to 1980 โœ… passed 54 ms
FilterPanel FilterPanel ArrowUp on empty To year sets it to 2026 โœ… passed 75 ms
FilterPanel FilterPanel shows validation error when year is below 1000 โœ… passed 115 ms
FilterPanel FilterPanel clamps typed year above 2030 to 2030 on From year field โœ… passed 80 ms
FilterPanel FilterPanel clamps typed year above 2030 to 2030 on To year field โœ… passed 80 ms
FilterPanel FilterPanel does not clamp years within valid range โœ… passed 61 ms
SearchBar SearchBar renders a search input โœ… passed 207 ms
SearchBar SearchBar shows the defaultValue in the input โœ… passed 21 ms
SearchBar SearchBar shows a clear button only when input has a value โœ… passed 85 ms
SearchBar SearchBar calls onSearch with empty string when clear button is clicked โœ… passed 37 ms
SearchBar SearchBar syncs input value when defaultValue prop changes โœ… passed 52 ms
SearchBar SearchBar debounce behaviour (fake timers) does not call onSearch immediately after input changes โœ… passed 26 ms
SearchBar SearchBar debounce behaviour (fake timers) calls onSearch after the 300 ms debounce window โœ… passed 15 ms
SearchBar SearchBar debounce behaviour (fake timers) does not call onSearch on initial mount โœ… passed 4 ms
SearchBar SearchBar debounce behaviour (fake timers) calls onSearch with the latest value after the user pauses typing โœ… passed 16 ms
SearchFilter SearchFilter renders search bar and filters button โœ… passed 239 ms
SearchFilter SearchFilter does not show active filters section when no filters are set โœ… passed 11 ms
SearchFilter SearchFilter pre-populates search input from URL param q โœ… passed 47 ms
SearchFilter SearchFilter pre-shows active filter chips from URL params โœ… passed 25 ms
SearchFilter SearchFilter pre-shows search chip from URL param q โœ… passed 9 ms
SearchFilter SearchFilter removing a chip removes it from the active filters โœ… passed 107 ms
SearchFilter SearchFilter Clear all removes all active filters โœ… passed 79 ms
SearchFilter SearchFilter shows year range chip after applying year filters via panel โœ… passed 216 ms
SearchFilter SearchFilter shows location chip after applying location filter via panel โœ… passed 172 ms
SearchFilter SearchFilter shows filter count badge on the Filters button when filters are active โœ… passed 23 ms
SearchFilter SearchFilter removing the year range chip removes it and clears search input value updates โœ… passed 45 ms
EmptyState EmptyState renders with default props โœ… passed 46 ms
EmptyState EmptyState displays a custom title โœ… passed 4 ms
EmptyState EmptyState displays a custom message โœ… passed 3 ms
EmptyState EmptyState does not render CTA button when actionLabel/onAction are not provided โœ… passed 9 ms
EmptyState EmptyState renders CTA button when actionLabel and onAction are provided โœ… passed 146 ms
EmptyState EmptyState calls onAction when CTA button is clicked โœ… passed 56 ms
EmptyState EmptyState accepts a custom icon component โœ… passed 7 ms
EmptyState EmptyState does not render CTA if only actionLabel is given without onAction โœ… passed 5 ms
ErrorState ErrorState renders with default props โœ… passed 234 ms
ErrorState ErrorState displays a custom title โœ… passed 6 ms
ErrorState ErrorState displays a custom message โœ… passed 4 ms
ErrorState ErrorState does not render retry button when onRetry is not provided โœ… passed 6 ms
ErrorState ErrorState renders retry button when onRetry is provided โœ… passed 53 ms
ErrorState ErrorState calls onRetry when retry button is clicked โœ… passed 44 ms
ErrorState ErrorState displays a custom retry label โœ… passed 17 ms
ErrorState ErrorState has role=alert for accessibility โœ… passed 12 ms
LoadingSkeleton Skeleton renders without crashing โœ… passed 37 ms
LoadingSkeleton Skeleton has animate-pulse class โœ… passed 3 ms
LoadingSkeleton Skeleton merges custom className โœ… passed 3 ms
LoadingSkeleton SkeletonCard renders multiple skeleton blocks โœ… passed 5 ms
LoadingSkeleton SkeletonPage renders without crashing โœ… passed 11 ms
LoadingSpinner LoadingSpinner renders with default props โœ… passed 183 ms
LoadingSpinner LoadingSpinner displays a custom message โœ… passed 8 ms
LoadingSpinner LoadingSpinner renders screen-reader text when no message is provided โœ… passed 4 ms
LoadingSpinner LoadingSpinner applies fullPage class when fullPage prop is true โœ… passed 4 ms
LoadingSpinner LoadingSpinner does not apply fullPage class by default โœ… passed 3 ms
LoadingSpinner LoadingSpinner merges custom className โœ… passed 2 ms
Toaster Toaster renders nothing when there are no toasts โœ… passed 35 ms
Toaster Toaster shows a success toast โœ… passed 264 ms
Toaster Toaster shows an error toast โœ… passed 60 ms
Toaster Toaster shows an info toast โœ… passed 35 ms
Toaster Toaster dismisses a toast when the dismiss button is clicked โœ… passed 82 ms
Toaster Toaster auto-dismisses after the specified duration โœ… passed 12 ms
Toaster useToast throws when used outside ToastProvider โœ… passed 9 ms
StoryCard truncateAtWord returns the original text when within the limit โœ… passed 2 ms
StoryCard truncateAtWord truncates at a word boundary and appends ellipsis โœ… passed 0 ms
StoryCard truncateAtWord does not cut mid-word when a space exists before the limit โœ… passed 0 ms
StoryCard truncateAtWord hard-cuts a single long word with no spaces โœ… passed 0 ms
StoryCard formatTimePeriod formats exact_year โœ… passed 0 ms
StoryCard formatTimePeriod formats approximate_year with c. prefix โœ… passed 0 ms
StoryCard formatTimePeriod formats decade โœ… passed 0 ms
StoryCard formatTimePeriod formats year_range โœ… passed 0 ms
StoryCard formatTimePeriod returns empty string for unknown time_type โœ… passed 0 ms
StoryCard StoryCard renders the story title โœ… passed 81 ms
StoryCard StoryCard renders the location name โœ… passed 11 ms
StoryCard StoryCard renders the formatted time period โœ… passed 10 ms
StoryCard StoryCard renders preview_text with a trailing ellipsis โœ… passed 10 ms
StoryCard StoryCard renders nothing for preview when preview_text is absent โœ… passed 11 ms
StoryCard StoryCard renders the contributor name โœ… passed 15 ms
StoryCard StoryCard does not render contributor name when absent โœ… passed 7 ms
StoryCard StoryCard card link points to /stories/:id โœ… passed 152 ms
StoryCard StoryCard renders year_range time period โœ… passed 12 ms
StoryCard StoryCard renders approximate_year time period โœ… passed 8 ms
StoryCard StoryCard renders decade time period โœ… passed 9 ms
StoryCard StoryCard renders heart as not liked by default โœ… passed 8 ms
StoryCard StoryCard renders heart as liked when user_has_liked is true โœ… passed 6 ms
โš ๏ธ **GitHub.com Fallback** โš ๏ธ