// @ts-check const { test, expect } = require('@playwright/test'); const fs = require('fs'); const path = require('path'); const RESULT_PATH = path.join(__dirname, '..', 'test-results', 'result.json'); function writeResult(result) { fs.mkdirSync(path.dirname(RESULT_PATH), { recursive: true }); fs.writeFileSync(RESULT_PATH, JSON.stringify(result)); } test.describe('twitter post', () => { let outcome = { success: false, error: 'Test did not complete' }; let outcomeFinalized = false; test.afterEach(async () => { writeResult(outcome); }); test('logs into Twitter and creates a post', async ({ page }) => { const username = process.env.TWITTER_USERNAME; const password = process.env.TWITTER_PASSWORD; const tweet = process.env.TWEET_TEXT; for (const [name, value] of Object.entries({ TWITTER_USERNAME: username, TWITTER_PASSWORD: password, TWEET_TEXT: tweet, })) { if (!value) { outcome = { success: false, error: `Missing required environment variable: ${name}` }; outcomeFinalized = true; throw new Error(outcome.error); } } try { await page.goto('https://twitter.com/i/flow/login'); // Wait for page to load await page.waitForLoadState('networkidle'); // Check for login form const usernameField = page.getByLabel(/username|phone|email/i).first(); if (!await usernameField.isVisible({ timeout: 10000 }).catch(() => false)) { outcome = { success: false, error: 'Twitter login form not found — page structure may have changed', }; outcomeFinalized = true; throw new Error(outcome.error); } // Fill username and proceed await usernameField.fill(username); await usernameField.press('Enter'); // Wait for password field or next step await page.waitForTimeout(2000); const passwordField = page.getByLabel(/password/i).first(); if (await passwordField.isVisible({ timeout: 10000 }).catch(() => false)) { await passwordField.fill(password); await passwordField.press('Enter'); } // Wait for login to complete try { await page.waitForURL('https://twitter.com/home', { timeout: 20000 }); } catch { // Check if we're logged in by looking for tweet button const tweetButton = page.getByRole('button', { name: /tweet|post/i }).first(); if (!await tweetButton.isVisible({ timeout: 5000 }).catch(() => false)) { const errorText = await page.textContent('body').catch(() => ''); outcome = { success: false, error: errorText.includes('username') || errorText.includes('password') ? 'Invalid Twitter credentials' : 'Twitter login did not complete — possible CAPTCHA, 2FA, or invalid credentials', }; outcomeFinalized = true; throw new Error(outcome.error); } } // Click the tweet button const tweetButton = page.getByRole('button', { name: /tweet|post/i }).first(); await tweetButton.click(); // Wait for tweet composer const tweetTextarea = page.getByRole('textbox', { name: /what is happening/i }).first(); if (!await tweetTextarea.isVisible({ timeout: 10000 }).catch(() => false)) { outcome = { success: false, error: 'Tweet composer not found — Twitter UI may have changed', }; outcomeFinalized = true; throw new Error(outcome.error); } // Fill tweet text await tweetTextarea.fill(tweet); // Click tweet/post button const postButton = page.getByRole('button', { name: /tweet|post/i }).nth(1); await expect(postButton).toBeEnabled({ timeout: 10000 }); await postButton.click(); // Wait for tweet to be posted try { await page.waitForURL(/(status|post)\//, { timeout: 20000 }); } catch { // Check if tweet was posted by looking for success indicators await page.waitForTimeout(3000); } // Get current URL (should be the tweet URL) outcome = { success: true, url: page.url() }; outcomeFinalized = true; expect(outcome.success).toBe(true); } catch (err) { if (!outcomeFinalized) { outcome = { success: false, error: err instanceof Error ? err.message : String(err) }; } throw err; } }); });