mirror of
https://github.com/CompeyDev/fxtwitter-docker.git
synced 2025-04-04 10:00:55 +01:00
Working tests!
This commit is contained in:
parent
790bcdbd78
commit
1810d885c4
9 changed files with 4946 additions and 259 deletions
19
jestconfig.json
Normal file
19
jestconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"testEnvironment": "miniflare",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)sx?$": "ts-jest"
|
||||
},
|
||||
"globals": {
|
||||
"BRANDING_NAME": "FixTweet",
|
||||
"BRANDING_NAME_DISCORD": "FixTweetBrandingDiscord",
|
||||
"DIRECT_MEDIA_DOMAINS": "d.fxtwitter.com,dl.fxtwitter.com",
|
||||
"MOSAIC_DOMAIN_LIST": "mosaic.fxtwitter.com",
|
||||
"API_HOST": "api.fxtwitter.com",
|
||||
"HOST_URL": "https://fxtwitter.com",
|
||||
"REDIRECT_URL": "https://github.com/dangeredwolf/FixTweet",
|
||||
"RELEASE_NAME": "fixtweet-test",
|
||||
"TEST": true
|
||||
},
|
||||
"testRegex": "/test/.*\\.test\\.ts$",
|
||||
"collectCoverageFrom": ["src/**/*.{ts,js}"]
|
||||
}
|
5073
package-lock.json
generated
5073
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,8 @@
|
|||
"log": "wrangler tail",
|
||||
"reload": "wrangler publish && wrangler tail",
|
||||
"prettier": "prettier --write .",
|
||||
"lint:eslint": "eslint --max-warnings=0 src"
|
||||
"lint:eslint": "eslint --max-warnings=0 src",
|
||||
"test": "jest --config jestconfig.json --verbose"
|
||||
},
|
||||
"author": "dangered wolf",
|
||||
"license": "MIT",
|
||||
|
@ -17,7 +18,7 @@
|
|||
"@cloudflare/workers-types": "^3.14.1",
|
||||
"@microsoft/eslint-formatter-sarif": "^3.0.0",
|
||||
"@sentry/webpack-plugin": "^1.19.0",
|
||||
"@types/service-worker-mock": "^2.0.1",
|
||||
"@types/jest": "^28.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"dotenv": "^16.0.1",
|
||||
|
@ -26,8 +27,10 @@
|
|||
"eslint-config-typescript": "^3.0.0",
|
||||
"eslint-plugin-optimize-regex": "^1.2.1",
|
||||
"eslint-plugin-sonarjs": "^0.15.0",
|
||||
"jest": "^28.1.3",
|
||||
"jest-environment-miniflare": "^2.6.0",
|
||||
"prettier": "^2.7.1",
|
||||
"service-worker-mock": "^2.0.5",
|
||||
"ts-jest": "^28.0.7",
|
||||
"ts-loader": "^9.3.1",
|
||||
"typescript": "^4.7.4",
|
||||
"webpack": "^5.74.0",
|
||||
|
|
|
@ -63,3 +63,8 @@ Allow: /watch?v=dQw4w9WgXcQ
|
|||
Disallow: /doing-harm-to-others
|
||||
Disallow: /taking-over-the-world`
|
||||
};
|
||||
|
||||
if (typeof TEST !== 'undefined') {
|
||||
/* Undici gets angry about unicode headers, this is a workaround. */
|
||||
Constants.RESPONSE_HEADERS['x-powered-by'] = 'Trans Rights';
|
||||
}
|
||||
|
|
2
src/env.d.ts
vendored
2
src/env.d.ts
vendored
|
@ -8,3 +8,5 @@ declare const API_HOST: string;
|
|||
|
||||
declare const SENTRY_DSN: string;
|
||||
declare const RELEASE_NAME: string;
|
||||
|
||||
declare const TEST: boolean | undefined;
|
||||
|
|
|
@ -140,13 +140,15 @@ router.get('*', async (request: Request) => {
|
|||
const url = new URL(request.url);
|
||||
|
||||
if (url.hostname === Constants.API_HOST) {
|
||||
return Response.redirect(Constants.API_DOCS_URL, 307);
|
||||
return Response.redirect(Constants.API_DOCS_URL, 302);
|
||||
}
|
||||
return Response.redirect(Constants.REDIRECT_URL, 307);
|
||||
return Response.redirect(Constants.REDIRECT_URL, 302);
|
||||
});
|
||||
|
||||
const cacheWrapper = async (event: FetchEvent): Promise<Response> => {
|
||||
const { request } = event;
|
||||
export const cacheWrapper = async (
|
||||
request: Request,
|
||||
event?: FetchEvent
|
||||
): Promise<Response> => {
|
||||
const userAgent = request.headers.get('User-Agent') || '';
|
||||
// https://developers.cloudflare.com/workers/examples/cache-api/
|
||||
const cacheUrl = new URL(
|
||||
|
@ -177,6 +179,7 @@ const cacheWrapper = async (event: FetchEvent): Promise<Response> => {
|
|||
switch (request.method) {
|
||||
case 'GET':
|
||||
if (cacheUrl.hostname !== Constants.API_HOST) {
|
||||
/* cache may be undefined in tests */
|
||||
const cachedResponse = await cache.match(cacheKey);
|
||||
|
||||
if (cachedResponse) {
|
||||
|
@ -188,12 +191,12 @@ const cacheWrapper = async (event: FetchEvent): Promise<Response> => {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const response = await router.handle(event.request, event);
|
||||
const response = await router.handle(request, event);
|
||||
|
||||
// Store the fetched response as cacheKey
|
||||
// Use waitUntil so you can return the response without blocking on
|
||||
// writing to cache
|
||||
event.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
event && event.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
|
||||
return response;
|
||||
/* Telegram sends this from Webpage Bot, and Cloudflare sends it if we purge cache, and we respect it.
|
||||
|
@ -219,10 +222,10 @@ const cacheWrapper = async (event: FetchEvent): Promise<Response> => {
|
|||
}
|
||||
};
|
||||
|
||||
const sentryWrapper = async (event: FetchEvent): Promise<void> => {
|
||||
const sentryWrapper = async (event: FetchEvent, test = false): Promise<void> => {
|
||||
let sentry: null | Toucan = null;
|
||||
|
||||
if (typeof SENTRY_DSN !== 'undefined') {
|
||||
if (typeof SENTRY_DSN !== 'undefined' && !test) {
|
||||
sentry = new Toucan({
|
||||
dsn: SENTRY_DSN,
|
||||
context: event, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Also includes 'request' -- no need to set it separately.
|
||||
|
@ -239,7 +242,7 @@ const sentryWrapper = async (event: FetchEvent): Promise<void> => {
|
|||
event.respondWith(
|
||||
(async (): Promise<Response> => {
|
||||
try {
|
||||
return await cacheWrapper(event);
|
||||
return await cacheWrapper(event.request, event);
|
||||
} catch (err: unknown) {
|
||||
sentry && sentry.captureException(err);
|
||||
|
||||
|
@ -256,9 +259,10 @@ const sentryWrapper = async (event: FetchEvent): Promise<void> => {
|
|||
);
|
||||
};
|
||||
|
||||
/*
|
||||
Event to receive web requests on Cloudflare Worker
|
||||
*/
|
||||
addEventListener('fetch', (event: FetchEvent) => {
|
||||
sentryWrapper(event);
|
||||
});
|
||||
/* May be undefined in test scenarios */
|
||||
if (typeof addEventListener !== 'undefined') {
|
||||
/* Event to receive web requests on Cloudflare Worker */
|
||||
addEventListener('fetch', (event: FetchEvent) => {
|
||||
sentryWrapper(event);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -196,8 +196,8 @@ export const handleStatus = async (
|
|||
tweet.poll.choices.forEach(choice => {
|
||||
// render bar
|
||||
const bar = '█'.repeat((choice.percentage / 100) * barLength);
|
||||
str += `${bar}
|
||||
${choice.label} (${choice.percentage}%)
|
||||
// eslint-disable-next-line no-irregular-whitespace
|
||||
str += `${bar}\n${choice.label} (${choice.percentage}%)
|
||||
`;
|
||||
});
|
||||
|
||||
|
|
57
test/index.test.ts
Normal file
57
test/index.test.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { cacheWrapper } from '../src/server';
|
||||
// import { webcrypto } from 'node:crypto';
|
||||
// const crypto = webcrypto;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// declare const global: any;
|
||||
|
||||
const botHeaders = { 'User-Agent': 'Discordbot/2.0' };
|
||||
const humanHeaders = {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
|
||||
};
|
||||
|
||||
describe('handle', () => {
|
||||
test('Home page redirect', async () => {
|
||||
const result = await cacheWrapper(
|
||||
new Request('https://fxtwitter.com', { method: 'GET' })
|
||||
);
|
||||
expect(result.status).toEqual(302);
|
||||
expect(result.headers.get('location')).toEqual(
|
||||
'https://github.com/dangeredwolf/FixTweet'
|
||||
);
|
||||
});
|
||||
|
||||
test('API fetch basic Tweet', async () => {
|
||||
const result = await cacheWrapper(
|
||||
new Request('https://api.fxtwitter.com/status/20', {
|
||||
method: 'GET',
|
||||
headers: botHeaders
|
||||
})
|
||||
);
|
||||
expect(result.status).toEqual(200);
|
||||
const response = (await result.json()) as APIResponse;
|
||||
expect(response).toBeTruthy();
|
||||
expect(response.code).toEqual(200);
|
||||
expect(response.message).toEqual('OK');
|
||||
|
||||
const tweet = response.tweet as APITweet;
|
||||
expect(tweet).toBeTruthy();
|
||||
expect(tweet.url).toEqual('https://twitter.com/jack/status/20');
|
||||
expect(tweet.id).toEqual('20');
|
||||
expect(tweet.text).toEqual('just setting up my twttr');
|
||||
expect(tweet.author.screen_name.toLowerCase()).toEqual('jack');
|
||||
expect(tweet.author.name).toBeTruthy();
|
||||
expect(tweet.author.avatar_url).toBeTruthy();
|
||||
expect(tweet.author.banner_url).toBeTruthy();
|
||||
expect(tweet.author.avatar_color).toBeTruthy();
|
||||
expect(tweet.replies).toBeGreaterThan(0);
|
||||
expect(tweet.retweets).toBeGreaterThan(0);
|
||||
expect(tweet.likes).toBeGreaterThan(0);
|
||||
expect(tweet.twitter_card).toEqual('tweet');
|
||||
expect(tweet.created_at).toEqual('Tue Mar 21 20:50:14 +0000 2006');
|
||||
expect(tweet.created_timestamp).toEqual(1142974214);
|
||||
expect(tweet.lang).toEqual('en');
|
||||
expect(tweet.replying_to).toBeNull();
|
||||
});
|
||||
});
|
|
@ -11,7 +11,7 @@
|
|||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"types": ["@cloudflare/workers-types", "@types/service-worker-mock"]
|
||||
"types": ["@cloudflare/workers-types", "@types/service-worker-mock", "@types/jest"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist", "test"]
|
||||
|
|
Loading…
Add table
Reference in a new issue