Skip to content
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

handles edge cases and better styles #2

Merged
merged 7 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 0 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
- [Submission Process](#submission-process)
- [Moderation System](#moderation-system)
- [Rate Limiting](#rate-limiting)
- [Customization](#customization)
- [Frontend Customization](#frontend-customization)
- [Backend Customization](#backend-customization)
- [Contributing](#contributing)

</details>
Expand Down Expand Up @@ -226,48 +223,6 @@ To maintain quality:
- Rate limits reset daily
- Exceeding the limit results in a notification tweet

## Customization

### Frontend Customization

The frontend can be customized in several ways:

1. **Styling**
- Modify `frontend/tailwind.config.js` for theme customization
- Update global styles in `frontend/src/index.css`
- Component-specific styles in respective component files

2. **Components**
- Add new components in `frontend/src/components/`
- Modify existing components for different layouts or functionality

3. **Configuration**
- Update API endpoints in environment variables
- Modify build settings in `vite.config.ts`

See the [Frontend README](./frontend/README.md) for detailed customization options.

### Backend Customization

The backend service can be extended and customized:

1. **Services**
- Add new services in `backend/src/services/`
- Modify existing services for different functionality
- Extend API endpoints as needed

2. **Configuration**
- Update environment variables for different integrations
- Modify admin settings in `src/config/`
- Adjust rate limits and other constraints

3. **Integration**
- Add new blockchain integrations
- Extend social media support
- Implement additional APIs

See the [Backend README](./backend/README.md) for detailed customization options.

## Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
Expand Down
18 changes: 18 additions & 0 deletions backend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @type {import('jest').Config} */
export default {
preset: "ts-jest",
testEnvironment: "node",
extensionsToTreatAsEsm: [".ts"],
moduleNameMapper: {
"^(\\.{1,2}/.*)\\.js$": "$1",
},
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
useESM: true,
},
],
},
setupFiles: ["<rootDir>/src/__tests__/setup.ts"],
};
7 changes: 5 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"scripts": {
"build": "bun build ./src/index.ts --target=bun --outdir=dist --format=esm",
"start": "bun run dist/index.js",
"dev": "bun run --watch src/index.ts"
"dev": "bun run --watch src/index.ts",
"test": "jest",
"test:watch": "jest --watch"
},
"browserslist": {
"production": [
Expand All @@ -27,13 +29,14 @@
"@types/ora": "^3.2.0",
"bun-types": "^1.1.40",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.1",
"typescript": "^5.3.3"
},
"dependencies": {
"@types/cors": "^2.8.17",
"agent-twitter-client": "^0.0.16",
"cors": "^2.8.5",
"@types/cors": "^2.8.17",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"ora": "^8.1.1",
Expand Down
90 changes: 90 additions & 0 deletions backend/src/__tests__/mocks/twitter-client.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Tweet } from "agent-twitter-client";

export class MockScraper {
private mockTweets: Tweet[] = [];
private _isLoggedIn = false;
private cookies: string[] = [];

// Method to add mock tweets for testing
public addMockTweet(tweet: Tweet) {
this.mockTweets.push(tweet);
}

// Method to clear mock tweets
public clearMockTweets() {
this.mockTweets = [];
}

async login(
username: string,
password: string,
email: string,
): Promise<void> {
this._isLoggedIn = true;
}

async logout(): Promise<void> {
this._isLoggedIn = false;
}

async isLoggedIn(): Promise<boolean> {
return this._isLoggedIn;
}

async setCookies(cookies: string[]): Promise<void> {
this.cookies = cookies;
}

async getCookies(): Promise<string[]> {
return this.cookies;
}

async getUserIdByScreenName(screenName: string): Promise<string> {
return `mock-user-id-${screenName}`;
}

async fetchSearchTweets(
query: string,
count: number,
mode: any,
cursor?: string,
): Promise<{ tweets: Tweet[] }> {
// If cursor is provided, simulate pagination by returning tweets after that ID
if (cursor) {
const cursorIndex = this.mockTweets.findIndex((t) => t.id === cursor);
if (cursorIndex !== -1) {
return {
tweets: this.mockTweets.slice(
cursorIndex + 1,
cursorIndex + 1 + count,
),
};
}
}

return {
tweets: this.mockTweets.slice(0, count),
};
}

async getTweet(tweetId: string): Promise<Tweet | null> {
return this.mockTweets.find((t) => t.id === tweetId) || null;
}

async sendTweet(message: string, replyToId?: string): Promise<Response> {
const mockResponse = {
json: async () => ({
data: {
create_tweet: {
tweet_results: {
result: {
rest_id: `mock-reply-${Date.now()}`,
},
},
},
},
}),
};
return mockResponse as Response;
}
}
83 changes: 83 additions & 0 deletions backend/src/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { beforeAll, mock } from "bun:test";

// Mock environment variables
process.env.PORT = "3000";
process.env.NODE_ENV = "test";

// Mock Bun server
const mockServer = {
upgrade: mock(() => true),
fetch: mock(() => new Response()),
publish: mock(() => {}),
unsubscribe: mock(() => {}),
reload: mock(() => {}),
pendingWebSockets: new Set(),
stop: mock(() => {}),
};

const mockFile = {
exists: mock(() => Promise.resolve(true)),
text: mock(() => Promise.resolve("")),
stream: mock(() => new ReadableStream()),
size: 0,
type: "text/plain",
};

// Create a proxy to handle server initialization
const serverProxy = new Proxy(mockServer, {
get: (target, prop) => {
if (prop === "upgrade") {
return (req: Request) => true;
}
return target[prop as keyof typeof target];
},
});

globalThis.Bun = {
serve: mock(() => serverProxy),
file: mock((path: string) => mockFile),
} as any;

// Mock logger
const mockLogger = {
info: mock(() => {}),
error: mock(() => {}),
debug: mock(() => {}),
};

const mockSpinner = {
startSpinner: mock(() => {}),
succeedSpinner: mock(() => {}),
failSpinner: mock(() => {}),
cleanup: mock(() => {}),
};

// Mock modules
import { logger } from "../utils/logger";
Object.assign(logger, mockLogger);
Object.assign(logger, mockSpinner);

// Mock config
import config from "../config/config";
Object.assign(config, {
twitter: {
username: "test_user",
password: "test_pass",
email: "[email protected]",
},
});

// Mock ADMIN_ACCOUNTS
import { ADMIN_ACCOUNTS } from "../config/admins";
(ADMIN_ACCOUNTS as any) = ["admin"];

// Mock server functions
import { main, broadcastUpdate } from "../index";
Object.assign(
main,
mock(() => Promise.resolve()),
);
Object.assign(
broadcastUpdate,
mock(() => {}),
);
Loading
Loading