Files
playwright-gitcode/test.js

302 lines
10 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as fs from "fs";
import axios from "axios";
import { chromium } from 'playwright'
import dotenv from 'dotenv';
dotenv.config();
(async () => {
const browser = await chromium.launch({
headless: true // 👈 Windows建议先开界面调试
});
// 👇 关键就在这里
let context = null
if (fs.existsSync('state.json')) {
console.log('✅ state.json 存在');
context = await browser.newContext({
storageState: 'state.json',
locale: "zh-CN"
});
} else {
console.log('❌ state.json 不存在');
context = await browser.newContext({
locale: "zh-CN"
})
}
const page = await context.newPage();
await page.goto('https://gitcode.com/setting/points');
await page.waitForTimeout(5000);
const isLogin = await page.locator('.g-user-avatar').isVisible();
if (isLogin) {
console.log('✅ 已登录');
runTasks(page)
} else {
console.log('❌ 未登录');
await page.getByText('密码登录').click();
await page.getByPlaceholder('请填写手机号/用户名/邮箱').fill('test');
await page.getByPlaceholder('请填写密码').fill('test');
await page.getByText('登录或注册完成代表你同意').click();
await page.getByText('我同意将账号、组织、仓库等信息提供给AtomGit进行 ').click();
await page.locator('button:has-text("登 录")').click();
await page.waitForTimeout(1000);
await context.storageState({ path: 'state.json' });
runTasks(page)
}
})();
async function runTasks(page) {
console.log('✅ 开始寻找每日任务');
const tasks = await page.locator('.novice-task-item-box').all();
console.log('✅ 共找到' + tasks.length + '个每日任务');
for (const task of tasks) {
const title = await task.locator('.task-card-title__label-text').innerText();
if (title.includes("更新项目")) {
const taskStat = await taskIsCompleted(task)
if (!taskStat) {
await doUpdateProject(page)
}
console.log('✅ 更新项目已完成');
} else if (title.includes("每日分享")) {
const taskStat = await taskIsCompleted(task)
if (!taskStat) {
await dailyShare(task, page)
}
console.log('✅ 每日分享已完成');
} else if (title.includes("每日签到")) {
const taskStat = await taskIsCompleted(task)
if (!taskStat) {
await dailyCheckInTask(task, page)
}
console.log('✅ 每日签到已完成');
} else if (title.includes("查看热门")) {
const taskStat = await taskIsCompleted(task)
if (!taskStat) {
await dailyViewTrending(task, page)
}
console.log('✅ 查看热门已完成');
} else if (title.includes("每日Star")) {
const taskStat = await taskIsCompleted(task)
if (!taskStat) {
await dailyViewStar(task, page)
}
console.log('✅ 每日Star已完成');
}
}
await page.waitForTimeout(2000);
await page.reload({ waitUntil: "domcontentloaded" });
await page.waitForTimeout(2000);
await page.locator('button.pickup-btn:has-text("一键领取")').click();
console.log('✅ 已完成所有任务,奖励已领取 , 开始寻找卡片, 判断所有是否完成和领取');
const tasks2 = await page.locator('.novice-task-item-box').all();
console.log('✅ 共找到' + tasks2.length + '个每日任务');
for (const task of tasks2) {
const isCompleted = await task.locator('.completed').count() > 0;
const title = await task.locator('.task-card-title__label-text').innerText();
console.log('✅ ' + title + ' 任务完成状态: ' + (isCompleted ? '已完成' : '未完成'));
}
await page.waitForTimeout(1000);
await sendFeishuText('✅ 已完成所有任务,奖励已领取');
process.exit(0)
}
async function taskIsCompleted(task) {
const rewardBtn = task.locator('button:has-text("领取奖励")');
// 如果存在领取奖励按钮 -> 说明任务已完成但奖励未领取
if (await rewardBtn.count() > 0) {
console.log('🎁 检测到可领取奖励,正在领取...');
await rewardBtn.click();
// 等待领取按钮消失 or completed 出现
await task.page().waitForTimeout(800);
const stillHasRewardBtn = await rewardBtn.count() > 0;
const isCompleted = await task.locator('.completed').count() > 0;
if (!stillHasRewardBtn || isCompleted) {
console.log('✅ 奖励领取成功');
return true;
}
console.log('⚠️ 已点击领取奖励,但状态未变化,可能领取失败或延迟刷新');
return false;
}
// 已完成标记
const isCompleted = await task.locator('.completed').count() > 0;
if (isCompleted) {
console.log('✅ 已完成,跳过');
return true;
}
return false;
}
async function doUpdateProject(page) {
console.log('👉 执行项目更新');
const testRepoUrl = process.env.GITCODE_TEST_REPO_URL;
if (!testRepoUrl) {
throw new Error('未配置 GITCODE_TEST_REPO_URL无法执行更新项目任务');
}
const context = page.context();
const newPage = await context.newPage();
await newPage.goto(testRepoUrl);
// 你可以自己补逻辑
const frame = newPage.frameLocator('#codeartside');
// 1⃣ 点击编辑器
await frame.locator('.monaco-editor').click({
position: { x: 200, y: 100 }
});
// 2⃣ 把光标移动到末尾(关键!)
await newPage.keyboard.press('Control+End');
// 3⃣ 追加内容
await newPage.keyboard.type(`\n测试图片生成功能
11
22
33`, { delay: 50 });
// 等按钮出现
await newPage.locator('button:has-text("提交修改")').click();
await page.waitForTimeout(1000);
const submitButton = newPage.locator('button:has-text("提交修改")').nth(1); // 0 是页面按钮1 是弹框按钮
await submitButton.click();
await newPage.waitForTimeout(500);
await newPage.close();
}
async function dailyShare(task, page) {
// 等待新页面打开
const [newPage] = await Promise.all([
page.context().waitForEvent('page'), // 等待新页面事件
task.locator('.toComplete').click()
]);
// 点击第一个
await newPage.waitForTimeout(1000);
await newPage.locator('.immediately-invite-btn').nth(0).click();
await newPage.waitForTimeout(2000);
await newPage.close();
}
async function dailyCheckInTask(task, page) {
await page.waitForTimeout(1000);
task.locator('button:has-text("签到")').click()
await page.waitForTimeout(1000);
}
async function dailyViewTrending(task, page) {
// 等待新页面打开
const [newPage] = await Promise.all([
page.context().waitForEvent('page'), // 等待新页面事件
task.locator('.toComplete').click()
])
await newPage.waitForSelector('.hot-selection .recommend-card');
// 获取第一个热门项目卡片
const firstHotProjectCard = await newPage.$('.hot-selection .recommend-card');
await newPage.waitForTimeout(1000);
// 点击它
const [newPage2] = await Promise.all([
newPage.context().waitForEvent('page'), // 等待新页面事件
await firstHotProjectCard.click()
])
await newPage2.waitForTimeout(2000);
newPage2.close()
newPage.close()
}
async function dailyViewStar(task, page) {
// 等待新页面打开
const [newPage] = await Promise.all([
page.context().waitForEvent('page'), // 等待新页面事件
task.locator('.toComplete').click()
])
// 等待元素出现在 DOM不要用 visible容易超时
await newPage.waitForSelector('.hot-selection-list a.recommend-card', { state: 'attached' });
const cards = newPage.locator('.hot-selection-list a.recommend-card');
const count = await cards.count();
console.log("热门项目数量:", count);
if (count === 0) {
throw new Error("没有找到热门项目");
}
await newPage.waitForTimeout(2000);
// 随机选一个
const index = Math.floor(Math.random() * count);
console.log("随机选择 index:", index);
// 点击并捕获新 tab
const [newPage2] = await Promise.all([
newPage.context().waitForEvent('page'),
cards.nth(index).click()
]);
// 等待 Star 按钮出现
const starBtn = newPage2.locator('#repo-header-tab .status-btn').filter({ hasText: 'Star' }).nth(1);
await newPage2.waitForTimeout(2000);
await starBtn.waitFor({ state: 'visible' });
// 判断是否已 Starred
const text = await starBtn.innerText();
await newPage2.waitForTimeout(2000);
if (text.includes('Starred')) {
// 已经 Starred -> 先取消
await starBtn.click();
// 等待变回 Star
await newPage2.waitForTimeout(500);
}
await starBtn.click();
await newPage2.waitForTimeout(2000);
newPage2.close()
newPage.close()
}
async function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}
async function sendFeishuText(text) {
const webhook = process.env.FEISHU_WEBHOOK;
if (!webhook) {
console.log('FEISHU_WEBHOOK 未配置,跳过飞书通知');
return;
}
const payload = {
msg_type: "text",
content: { text }
};
for (let i = 1; i <= 5; i++) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10秒超时
const res = await fetch(webhook, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: controller.signal
});
clearTimeout(timeout);
const data = await res.text();
console.log("Feishu response:", data);
return;
} catch (err) {
console.error(`Feishu send failed (attempt ${i})`, err);
await sleep(3000);
}
}
throw new Error("Feishu webhook failed after retries");
}