Use twitter safe relay
CI / test (pull_request) Has been cancelled

This commit is contained in:
2026-06-24 03:39:34 +09:00
parent b771e827aa
commit 1f6e228272
66 changed files with 597 additions and 1720 deletions
@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { TwitterClient } from '../src/lib/twitter-client.js';
import { validCookies } from './twitter-client-fixtures.js';
import { testRelayBaseUrl } from './twitter-client-fixtures.js';
const originalFetch = global.fetch;
@@ -10,26 +10,22 @@ afterEach(() => {
});
describe('TwitterClient constructor', () => {
it('should throw if authToken is missing', () => {
expect(
() =>
new TwitterClient({
cookies: { authToken: null, ct0: 'test', cookieHeader: null, source: null },
}),
).toThrow('Both authToken and ct0 cookies are required');
it('throws if relay base URL is missing', () => {
const originalRelayBaseUrl = process.env.TWITTER_RELAY_BASE_URL;
delete process.env.TWITTER_RELAY_BASE_URL;
try {
expect(() => new TwitterClient({})).toThrow('TWITTER_RELAY_BASE_URL is required');
} finally {
if (originalRelayBaseUrl === undefined) {
delete process.env.TWITTER_RELAY_BASE_URL;
} else {
process.env.TWITTER_RELAY_BASE_URL = originalRelayBaseUrl;
}
}
});
it('should throw if ct0 is missing', () => {
expect(
() =>
new TwitterClient({
cookies: { authToken: 'test', ct0: null, cookieHeader: null, source: null },
}),
).toThrow('Both authToken and ct0 cookies are required');
});
it('should create client with valid cookies', () => {
const client = new TwitterClient({ cookies: validCookies });
it('creates client with relay base URL', () => {
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
expect(client).toBeInstanceOf(TwitterClient);
});
});
@@ -61,7 +57,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(true);
@@ -69,8 +65,12 @@ describe('TwitterClient tweet', () => {
expect(mockFetch).toHaveBeenCalledTimes(1);
const [url, options] = mockFetch.mock.calls[0];
expect(url).toContain('CreateTweet');
expect(String(url)).toContain(`${testRelayBaseUrl}/i/api/graphql/`);
expect(String(url)).toContain('CreateTweet');
expect(options.method).toBe('POST');
expect(options.headers).not.toHaveProperty('cookie');
expect(options.headers).not.toHaveProperty('authorization');
expect(options.headers).not.toHaveProperty('x-csrf-token');
const body = JSON.parse(options.body);
expect(body.variables.tweet_text).toBe('Hello world!');
@@ -94,7 +94,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!', ['111', '222']);
expect(result.success).toBe(true);
@@ -136,7 +136,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(true);
@@ -146,7 +146,7 @@ describe('TwitterClient tweet', () => {
const [firstUrl] = mockFetch.mock.calls[0];
const [thirdUrl] = mockFetch.mock.calls[2];
expect(String(firstUrl)).toContain('/CreateTweet');
expect(String(thirdUrl)).toBe('https://x.com/i/api/graphql');
expect(String(thirdUrl)).toBe(`${testRelayBaseUrl}/i/api/graphql`);
});
it('should handle API errors', async () => {
@@ -157,7 +157,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Test');
expect(result.success).toBe(false);
@@ -184,7 +184,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(true);
@@ -212,7 +212,7 @@ describe('TwitterClient tweet', () => {
text: async () => 'Forbidden',
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(false);
@@ -242,7 +242,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(false);
@@ -268,7 +268,7 @@ describe('TwitterClient tweet', () => {
json: async () => ({}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(false);
@@ -283,7 +283,7 @@ describe('TwitterClient tweet', () => {
text: async () => 'Forbidden',
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Test');
expect(result.success).toBe(false);
@@ -293,7 +293,7 @@ describe('TwitterClient tweet', () => {
it('should handle network errors', async () => {
mockFetch.mockRejectedValueOnce(new Error('Network error'));
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Test');
expect(result.success).toBe(false);
@@ -316,7 +316,7 @@ describe('TwitterClient tweet', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.tweet('Hello world!');
expect(result.success).toBe(false);
@@ -348,7 +348,7 @@ describe('TwitterClient reply', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.reply('This is a reply', '1234567890');
expect(result.success).toBe(true);
@@ -382,7 +382,7 @@ describe('TwitterClient reply', () => {
}),
});
const client = new TwitterClient({ cookies: validCookies });
const client = new TwitterClient({ relayBaseUrl: testRelayBaseUrl });
const result = await client.reply('This is a reply', '1234567890', ['111', '222']);
expect(result.success).toBe(true);