-
Notifications
You must be signed in to change notification settings - Fork 38
fix(tests): resolve unit test failures on development #2055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| import { describe, expect, it, vi } from 'vitest'; | ||
|
|
||
| // Mock clientEnvs before importing the module under test so that | ||
| // buildPostImageUrl has a deterministic CDN base URL. | ||
| vi.mock('expo-app/env/clientEnvs', () => ({ | ||
| clientEnvs: { | ||
| EXPO_PUBLIC_R2_PUBLIC_URL: 'https://cdn.example.com', | ||
| }, | ||
| })); | ||
|
|
||
| // Also mock getRelativeTime so that formatRelativeDate has a predictable | ||
| // alias target that does not depend on the current clock. | ||
| vi.mock('expo-app/lib/utils/getRelativeTime', () => ({ | ||
| getRelativeTime: (input: string | Date) => `relative(${String(input)})`, | ||
| })); | ||
|
|
||
| import type { Comment, Post } from '../../types'; | ||
| import { buildPostImageUrl, formatAuthorName, formatRelativeDate } from '../index'; | ||
|
|
||
| const basePost: Post = { | ||
| id: 1, | ||
| userId: 42, | ||
| caption: 'hello', | ||
| images: [], | ||
| createdAt: '2024-01-01T00:00:00.000Z', | ||
| updatedAt: '2024-01-01T00:00:00.000Z', | ||
| likeCount: 0, | ||
| commentCount: 0, | ||
| likedByMe: false, | ||
| }; | ||
|
|
||
| const baseComment: Comment = { | ||
| id: 1, | ||
| postId: 1, | ||
| userId: 42, | ||
| content: 'nice', | ||
| parentCommentId: null, | ||
| createdAt: '2024-01-01T00:00:00.000Z', | ||
| updatedAt: '2024-01-01T00:00:00.000Z', | ||
| likeCount: 0, | ||
| likedByMe: false, | ||
| }; | ||
|
|
||
| describe('feed/utils', () => { | ||
| // --------------------------------------------------------------------------- | ||
| // buildPostImageUrl | ||
| // --------------------------------------------------------------------------- | ||
| describe('buildPostImageUrl', () => { | ||
| it('joins the CDN base URL with the image key', () => { | ||
| expect(buildPostImageUrl('posts/abc.jpg')).toBe('https://cdn.example.com/posts/abc.jpg'); | ||
| }); | ||
|
|
||
| it('does not double-encode or trim the image key', () => { | ||
| expect(buildPostImageUrl('folder/sub folder/image (1).png')).toBe( | ||
| 'https://cdn.example.com/folder/sub folder/image (1).png', | ||
| ); | ||
| }); | ||
|
|
||
| it('handles an empty image key by returning the base URL with a trailing slash', () => { | ||
| expect(buildPostImageUrl('')).toBe('https://cdn.example.com/'); | ||
| }); | ||
| }); | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // formatAuthorName | ||
| // --------------------------------------------------------------------------- | ||
| describe('formatAuthorName', () => { | ||
| it('returns "Unknown" when the author is missing', () => { | ||
| expect(formatAuthorName(basePost)).toBe('Unknown'); | ||
| expect(formatAuthorName(baseComment)).toBe('Unknown'); | ||
| }); | ||
|
|
||
| it('returns "first last" when both names are present', () => { | ||
| const post: Post = { | ||
| ...basePost, | ||
| author: { id: 1, firstName: 'Ada', lastName: 'Lovelace' }, | ||
| }; | ||
| expect(formatAuthorName(post)).toBe('Ada Lovelace'); | ||
| }); | ||
|
|
||
| it('returns just the first name when only firstName is present', () => { | ||
| const post: Post = { | ||
| ...basePost, | ||
| author: { id: 1, firstName: 'Ada', lastName: null }, | ||
| }; | ||
| expect(formatAuthorName(post)).toBe('Ada'); | ||
| }); | ||
|
|
||
| it('returns just the last name when only lastName is present', () => { | ||
| const post: Post = { | ||
| ...basePost, | ||
| author: { id: 1, firstName: null, lastName: 'Lovelace' }, | ||
| }; | ||
| expect(formatAuthorName(post)).toBe('Lovelace'); | ||
| }); | ||
|
|
||
| it('returns "User" when the author exists but both names are null', () => { | ||
| const post: Post = { | ||
| ...basePost, | ||
| author: { id: 1, firstName: null, lastName: null }, | ||
| }; | ||
| expect(formatAuthorName(post)).toBe('User'); | ||
| }); | ||
|
|
||
| it('also works for Comment entities', () => { | ||
| const comment: Comment = { | ||
| ...baseComment, | ||
| author: { id: 1, firstName: 'Grace', lastName: 'Hopper' }, | ||
| }; | ||
| expect(formatAuthorName(comment)).toBe('Grace Hopper'); | ||
| }); | ||
| }); | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // formatRelativeDate (deprecated alias of getRelativeTime) | ||
| // --------------------------------------------------------------------------- | ||
| describe('formatRelativeDate', () => { | ||
| it('delegates to getRelativeTime', () => { | ||
| expect(formatRelativeDate('2024-01-01T00:00:00.000Z')).toBe( | ||
| 'relative(2024-01-01T00:00:00.000Z)', | ||
| ); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,150 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { describe, expect, it, vi } from 'vitest'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { PackTemplate, PackTemplateItem } from '../../types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // which also re-exports uploadImage (expo-file-system) and computeCategories | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // (expo-app/features/auth/store). Replace the barrel with the real pure | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // conversion helpers so the test stays in a Node environment. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.mock('expo-app/features/packs/utils', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const fromGrams = await import('expo-app/features/packs/utils/convertFromGrams'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const toGrams = await import('expo-app/features/packs/utils/convertToGrams'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| convertFromGrams: fromGrams.convertFromGrams, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| convertToGrams: toGrams.convertToGrams, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+15
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | |
| // which also re-exports uploadImage (expo-file-system) and computeCategories | |
| // (expo-app/features/auth/store). Replace the barrel with the real pure | |
| // conversion helpers so the test stays in a Node environment. | |
| vi.mock('expo-app/features/packs/utils', async () => { | |
| const fromGrams = await import('expo-app/features/packs/utils/convertFromGrams'); | |
| const toGrams = await import('expo-app/features/packs/utils/convertToGrams'); | |
| return { | |
| convertFromGrams: fromGrams.convertFromGrams, | |
| convertToGrams: toGrams.convertToGrams, | |
| }; | |
| }); | |
| import { convertFromGrams } from 'expo-app/features/packs/utils/convertFromGrams'; | |
| import { convertToGrams } from 'expo-app/features/packs/utils/convertToGrams'; | |
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | |
| // which also re-exports uploadImage (expo-file-system) and computeCategories | |
| // (expo-app/features/auth/store). Replace the barrel with the real pure | |
| // conversion helpers so the test stays in a Node environment. | |
| vi.mock('expo-app/features/packs/utils', () => ({ | |
| convertFromGrams, | |
| convertToGrams, | |
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test locks in behavior that produces URLs containing spaces/parentheses unencoded, which is not a valid/robust URL form in many clients. If
buildPostImageUrlis intended to return a safe URL, update the expectation to percent-encode reserved characters (e.g., spaces as%20), or alternatively change the test input to an already-encoded key and assert it is not double-encoded (so the test still covers the intended contract reliably).