diff --git a/mobile/__tests__/CreatePost.test.js b/mobile/__tests__/CreatePost.test.js
new file mode 100644
index 00000000..06258433
--- /dev/null
+++ b/mobile/__tests__/CreatePost.test.js
@@ -0,0 +1,78 @@
+import React from 'react';
+import { render, fireEvent, waitFor } from '@testing-library/react-native';
+import CreatePost from '../src/pages/CreatePost'; // Adjust the import as necessary
+import { useAuth } from '../src/hooks/useAuth'; // Adjust the import path as necessary
+
+// Mock useAuth hook
+jest.mock('../src/hooks/useAuth', () => ({
+ useAuth: () => ({
+ accessToken: 'mockAccessToken', // Provide a default or mock value
+ userId: 'mockUserId',
+ }),
+}));
+
+jest.mock('node-fetch', () => require('jest-fetch-mock'));
+
+describe('CreatePost Component', () => {
+
+ it('toggles tag selection', () => {
+ const { getByText, getByTestId } = render();
+
+ const tagChip = getByText('Tech'); // Assuming 'Tech' is the text of the tag chip
+ fireEvent.press(tagChip);
+
+ expect(getByText("Tech").props.style.backgroundColor).toBe("#007BFF");
+ });
+
+ it('creates a post successfully', async () => {
+ const postData = {
+ title: "Test Post Title",
+ content: "This is the content of the post.",
+ tags: ["Tech", "Science"]
+ };
+
+ fetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => postData,
+ });
+
+ const { getByPlaceholderText, getByText } = render();
+ const titleInput = getByPlaceholderText("Title");
+ const contentInput = getByPlaceholderText("Content...");
+
+ fireEvent.changeText(titleInput, postData.title);
+ fireEvent.changeText(contentInput, postData.content);
+
+ fireEvent.press(getByText("Tech"));
+ fireEvent.press(getByText("Science"));
+
+ fireEvent.press(getByText("Create Post"));
+
+ await waitFor(() => getByText("Post created successfully!"));
+
+ expect(getByText("Post created successfully!")).toBeTruthy();
+ });
+
+ it('handles stock search correctly', async () => {
+ const { getByPlaceholderText, findByText } = render();
+
+ const searchInput = getByPlaceholderText("Search stocks...");
+ fireEvent.changeText(searchInput, "Apple");
+
+ const stockName = await findByText("Apple (AAPL)");
+
+ expect(stockName).toBeTruthy();
+ });
+
+ it('displays an error when stock not found', async () => {
+ const { getByPlaceholderText, queryByText } = render();
+
+ const searchInput = getByPlaceholderText("Search stocks...");
+ fireEvent.changeText(searchInput, "NonExistentStock");
+
+ const errorMessage = await waitFor(() => queryByText("Stock not found"));
+
+ expect(errorMessage).toBeTruthy();
+ });
+
+});
diff --git a/mobile/__tests__/Post.test.js b/mobile/__tests__/Post.test.js
new file mode 100644
index 00000000..f918a04a
--- /dev/null
+++ b/mobile/__tests__/Post.test.js
@@ -0,0 +1,170 @@
+import React from 'react';
+import renderer from 'react-test-renderer';
+import { render, waitFor, fireEvent } from '@testing-library/react-native';
+import Post from '../src/pages/Post'; // Adjust the import as necessary
+
+jest.mock('node-fetch', () => require('jest-fetch-mock'));
+
+describe('Post Component', () => {
+ it('should match snapshot', () => {
+ const postData = {
+ postId: '1',
+ author: 'John Doe',
+ userMap: {},
+ post: {
+ title: 'Test Post Title',
+ created_at: '2024-12-16T00:00:00Z',
+ tags: [{ id: 1, name: 'Test Tag' }],
+ content: 'This is a test post content.',
+ stocks: [1],
+ liked_by: [],
+ },
+ };
+
+ const tree = renderer.create().toJSON();
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should fetch post data and update state', async () => {
+ const mockPost = {
+ title: 'Test Post Title',
+ created_at: '2024-12-16T00:00:00Z',
+ tags: [{ id: 1, name: 'Test Tag' }],
+ content: 'This is a test post content.',
+ stocks: [1],
+ liked_by: [],
+ };
+
+ fetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockPost,
+ });
+
+ const { getByText } = render();
+
+ await waitFor(() => getByText('Test Post Title'));
+
+ expect(getByText('Test Post Title')).toBeTruthy();
+ });
+
+ it('should handle fetch error', async () => {
+ fetch.mockResolvedValueOnce({
+ ok: false,
+ });
+
+ const { queryByText } = render();
+
+ await waitFor(() => queryByText('Loading...'));
+
+ expect(queryByText('Test Post Title')).toBeNull();
+ });
+
+ it('should fetch comments and update state', async () => {
+ const mockComments = [
+ { id: 1, user_id: '2', content: 'Test comment 1' },
+ { id: 2, user_id: '3', content: 'Test comment 2' },
+ ];
+
+ fetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockComments,
+ });
+
+ const { getByText } = render();
+
+ await waitFor(() => getByText('Test comment 1'));
+
+ expect(getByText('Test comment 1')).toBeTruthy();
+ expect(getByText('Test comment 2')).toBeTruthy();
+ });
+
+ it('should handle fetch comments error', async () => {
+ fetch.mockResolvedValueOnce({
+ ok: false,
+ });
+
+ const { queryByText } = render();
+
+ await waitFor(() => queryByText('Loading...'));
+
+ expect(queryByText('Test comment 1')).toBeNull();
+ });
+
+ it('should post a comment and update the state', async () => {
+ const newComment = { post_id: '1', content: 'New comment' };
+ const mockResponse = { id: 3, user_id: '4', content: 'New comment' };
+
+ fetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockResponse,
+ });
+
+ const { getByText, getByPlaceholderText, getByTestId } = render(
+
+ );
+
+ fireEvent.changeText(getByPlaceholderText('Write a comment...'), 'New comment');
+ fireEvent.press(getByTestId('submit-button'));
+
+ await waitFor(() => getByText('New comment'));
+
+ expect(getByText('New comment')).toBeTruthy();
+ });
+
+ it('should handle post comment error', async () => {
+ fetch.mockResolvedValueOnce({
+ ok: false,
+ });
+
+ const { getByPlaceholderText } = render(
+
+ );
+
+ fireEvent.changeText(getByPlaceholderText('Write a comment...'), 'New comment');
+ fireEvent.press(getByTestId('submit-button'));
+
+ await waitFor(() => expect(Alert.alert).toHaveBeenCalledWith('Error liking the post: 400'));
+
+ expect(Alert.alert).toHaveBeenCalled();
+ });
+
+ it('should post a like and update the state', async () => {
+ fetch.mockResolvedValueOnce({
+ ok: true,
+ });
+
+ const { getByText } = render();
+
+ fireEvent.press(getByText('👍 Like'));
+
+ await waitFor(() => getByText('👍 Liked'));
+
+ expect(getByText('👍 Liked')).toBeTruthy();
+ });
+
+ it('should handle post like error', async () => {
+ fetch.mockResolvedValueOnce({
+ ok: false,
+ });
+
+ const { getByText } = render();
+
+ fireEvent.press(getByText('👍 Like'));
+
+ await waitFor(() => expect(Alert.alert).toHaveBeenCalledWith('Error liking the post: 400'));
+
+ expect(Alert.alert).toHaveBeenCalled();
+ });
+
+ it('should open and close the comment input modal', () => {
+ const { getByText, queryByText } = render();
+
+ fireEvent.press(getByText('💬 Add Comment'));
+
+ expect(queryByText('Write a comment...')).toBeTruthy();
+
+ fireEvent.press(getByText('Cancel'));
+
+ expect(queryByText('Write a comment...')).toBeNull();
+ });
+});
diff --git a/mobile/package-lock.json b/mobile/package-lock.json
index 8c8e48c7..798e6d61 100644
--- a/mobile/package-lock.json
+++ b/mobile/package-lock.json
@@ -8,6 +8,7 @@
"name": "mobile",
"version": "0.0.1",
"dependencies": {
+ "@react-native-picker/picker": "^2.10.2",
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/drawer": "^6.7.2",
"@react-navigation/native": "^6.1.18",
@@ -3886,6 +3887,15 @@
"node": ">=8"
}
},
+ "node_modules/@react-native-picker/picker": {
+ "version": "2.10.2",
+ "resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.10.2.tgz",
+ "integrity": "sha512-kr3OvCRwTYjR/OKlb52k4xmQVU7dPRIALqpyiihexdJxEgvc1smnepgqCeM9oXmNSG4YaV5/RSxFlLC5Z/T/Eg==",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/@react-native/assets-registry": {
"version": "0.75.4",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.75.4.tgz",
@@ -10880,10 +10890,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
-
-
"license": "MIT",
-
"engines": {
"node": ">=18"
}
diff --git a/mobile/package.json b/mobile/package.json
index cb8c920c..2826d412 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -10,6 +10,7 @@
"test": "jest"
},
"dependencies": {
+ "@react-native-picker/picker": "^2.10.2",
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/drawer": "^6.7.2",
"@react-navigation/native": "^6.1.18",