diff --git a/.github/workflows/.reusable-docker-e2e-tests.yml b/.github/workflows/.reusable-docker-e2e-tests.yml index d4202ab771c4..247361ecb3f4 100644 --- a/.github/workflows/.reusable-docker-e2e-tests.yml +++ b/.github/workflows/.reusable-docker-e2e-tests.yml @@ -153,7 +153,6 @@ jobs: cd e2e zip -r playwright-report.zip playwright-report/ || echo "Failed to zip report" cd .. - npm install --no-save @slack/web-api npx -y tsx e2e/slack-e2e-reporter.ts env: SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} diff --git a/frontend/api/slack-client.js b/frontend/api/slack-client.js index dc388d2e47b8..0f719e4696af 100644 --- a/frontend/api/slack-client.js +++ b/frontend/api/slack-client.js @@ -1,22 +1,26 @@ -const { WebClient } = require('@slack/web-api') - if (!process.env.SLACK_TOKEN) { return } -const web = new WebClient(process.env.SLACK_TOKEN) +const SLACK_TOKEN = process.env.SLACK_TOKEN async function toChannel(message, channel) { // eslint-disable-next-line - console.log(`sending to channel: ${channel} message: ${message}`); + console.log(`sending to channel: ${channel} message: ${message}`) try { - await web.chat.postMessage({ - channel: `#${channel}`, - text: message, + const res = await fetch('https://slack.com/api/chat.postMessage', { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + Authorization: `Bearer ${SLACK_TOKEN}`, + }, + body: JSON.stringify({ channel: `#${channel}`, text: message }), }) + const data = await res.json() + if (!data.ok) throw new Error(data.error) } catch (error) { // eslint-disable-next-line - console.log(`Error posting to Slack:${error}`); + console.log(`Error posting to Slack:${error}`) } } diff --git a/frontend/e2e/slack-e2e-reporter.ts b/frontend/e2e/slack-e2e-reporter.ts index c292d46b4963..98694bd29cc3 100644 --- a/frontend/e2e/slack-e2e-reporter.ts +++ b/frontend/e2e/slack-e2e-reporter.ts @@ -1,6 +1,5 @@ import * as fs from 'fs'; import * as path from 'path'; -import { WebClient } from '@slack/web-api'; const SLACK_TOKEN = process.env.SLACK_TOKEN; const CHANNEL_ID = 'C0102JZRG3G'; // infra_tests channel ID @@ -8,6 +7,20 @@ const failedJsonPath = path.join(__dirname, 'test-results', 'failed.json'); const failedData = JSON.parse(fs.readFileSync(failedJsonPath, 'utf-8')); const failedCount = failedData.failedTests?.length || 0; +async function slackPost(endpoint: string, body: Record): Promise { + const res = await fetch(`https://slack.com/api/${endpoint}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + Authorization: `Bearer ${SLACK_TOKEN}`, + }, + body: JSON.stringify(body), + }); + const data = await res.json() as { ok: boolean; error?: string }; + if (!data.ok) throw new Error(`Slack ${endpoint} error: ${data.error}`); + return data; +} + async function uploadFile(filePath: string): Promise { if (!SLACK_TOKEN) { console.log('Slack token not specified, skipping upload'); @@ -16,14 +29,28 @@ async function uploadFile(filePath: string): Promise { const epoch = Date.now(); const filename = `playwright-report-${epoch}.zip`; + const fileBytes = fs.readFileSync(filePath); + const fileSize = fileBytes.byteLength; console.log(`Uploading ${filePath}`); + const urlRes = await slackPost('files.getUploadURLExternal', { + filename, + length: fileSize, + }) as { upload_url: string; file_id: string }; + - const slackClient = new WebClient(SLACK_TOKEN); - await slackClient.files.uploadV2({ + const uploadRes = await fetch(urlRes.upload_url, { + method: 'POST', + headers: { 'Content-Type': 'application/octet-stream' }, + body: fileBytes, + }); + if (!uploadRes.ok) { + throw new Error(`Upload to pre-signed URL failed: ${uploadRes.status} ${uploadRes.statusText}`); + } + + await slackPost('files.completeUploadExternal', { + files: [{ id: urlRes.file_id, title: filename }], channel_id: CHANNEL_ID, - file: fs.createReadStream(filePath), - filename, }); } @@ -33,17 +60,10 @@ function postMessage(message: string): Promise { return Promise.resolve(); } - const slackClient = new WebClient(SLACK_TOKEN); - return slackClient.chat.postMessage({ - channel: CHANNEL_ID, - text: message, - }); + return slackPost('chat.postMessage', { channel: CHANNEL_ID, text: message }); } -function notifyFailure( - failedCount: number, - failedTests: any[], -): Promise { +function notifyFailure(failedCount: number, failedTests: any[]): Promise { const actionUrl = process.env.GITHUB_ACTION_URL || ''; if (!actionUrl) { console.log('No GITHUB_ACTION_URL set, skipping Slack notification'); @@ -56,16 +76,11 @@ function notifyFailure( const prTitle = process.env.PR_TITLE; const prUrl = process.env.PR_URL; - // Build PR info line const prInfo = prNumber && prUrl ? `*PR:* <${prUrl}|#${prNumber}>${prTitle ? ` - ${prTitle}` : ''}\n` : ''; - // Build failed tests list (inline, limit to first 3) - const testNames = failedTests - .slice(0, 3) - .map((test) => test.title) - .join(', '); + const testNames = failedTests.slice(0, 3).map((t) => t.title).join(', '); const moreTests = failedCount > 3 ? ` +${failedCount - 3} more` : ''; const message = `❌ E2E Tests Failed @@ -94,7 +109,6 @@ async function main() { await notifyFailure(failedCount, failedData.failedTests || []); console.log('Slack notification sent successfully'); - // Upload HTML report if zip file exists const reportZipPath = path.join(__dirname, 'playwright-report.zip'); if (fs.existsSync(reportZipPath)) { console.log('Uploading HTML report...'); diff --git a/frontend/package.json b/frontend/package.json index cf87373dceb1..826f7b07ba2c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -44,8 +44,7 @@ "react": "$react", "react-dom": "$react-dom", "@types/react": "$@types/react", - "@types/react-dom": "$@types/react-dom", - "axios": "^1.16.0" + "@types/react-dom": "$@types/react-dom" }, "dependencies": { "@amplitude/analytics-browser": "^2.11.3", @@ -74,7 +73,6 @@ "@rspack/plugin-react-refresh": "^1.6.2", "@sentry/browser": "^7.119.1", "@sentry/webpack-plugin": "2.22.7", - "@slack/web-api": "^6.9.1", "array-find-index": "^1.0.2", "body-parser": "^2.2.2", "bootstrap": "5.2.2",