fix(community): persist post liked status in MySQL and local storage to prevent state loss on page switch
这个提交包含在:
@@ -945,6 +945,60 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安
|
||||
expect(emojiRegex.test(communityContent)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('22. 友圈广场点赞状态跨页面持久化与防重闭环验证 (MySQL post_likes & UniApp 同步)', () => {
|
||||
it('MySQL 结构中必须包含 post_likes 用户点赞明细表及唯一防重键', () => {
|
||||
const mysqlPath = path.join(rootDir, 'server', 'src', 'db', 'mysql.ts');
|
||||
const content = fs.readFileSync(mysqlPath, 'utf-8');
|
||||
expect(content).toContain('CREATE TABLE IF NOT EXISTS post_likes');
|
||||
expect(content).toContain('post_id');
|
||||
expect(content).toContain('user_id');
|
||||
expect(content).toContain('uq_post_user');
|
||||
});
|
||||
|
||||
it('Repository getPosts 与 likePost 必须支持用户点赞状态关联查询与双向落盘', () => {
|
||||
const repoPath = path.join(rootDir, 'server', 'src', 'db', 'repository.ts');
|
||||
const content = fs.readFileSync(repoPath, 'utf-8');
|
||||
expect(content).toContain('SELECT post_id FROM post_likes WHERE user_id = ?');
|
||||
expect(content).toContain('INSERT IGNORE INTO post_likes');
|
||||
expect(content).toContain('DELETE FROM post_likes WHERE post_id = ? AND user_id = ?');
|
||||
});
|
||||
|
||||
it('服务端路由 /api/posts 与 /api/posts/:id/like 必须支持透传 userId 与 action', () => {
|
||||
const indexPath = path.join(rootDir, 'server', 'src', 'index.ts');
|
||||
const content = fs.readFileSync(indexPath, 'utf-8');
|
||||
expect(content).toContain("app.get('/api/posts'");
|
||||
expect(content).toContain("app.post('/api/posts/:id/like'");
|
||||
expect(content).toContain("'like' | 'unlike'");
|
||||
});
|
||||
|
||||
it('UniApp API 层与社区页面必须通过本地存储双重保障切页不丢点赞状态', () => {
|
||||
const apiPath = path.join(rootDir, 'pwuniapp', 'common', 'api.js');
|
||||
const apiContent = fs.readFileSync(apiPath, 'utf-8');
|
||||
expect(apiContent).toContain('COMMUNITY_LIKED_POST_IDS');
|
||||
|
||||
const communityPath = path.join(rootDir, 'pwuniapp', 'pages', 'community', 'index.vue');
|
||||
const communityContent = fs.readFileSync(communityPath, 'utf-8');
|
||||
expect(communityContent).toContain('COMMUNITY_LIKED_POST_IDS');
|
||||
expect(communityContent).toContain('syncInitialLikedState');
|
||||
expect(communityContent).toContain('uni.setStorageSync(\'COMMUNITY_LIKED_POST_IDS\'');
|
||||
});
|
||||
|
||||
it('所有新增的点赞持久化代码与测试严禁包含任何系统 Emoji 违规字符', () => {
|
||||
const mysqlPath = path.join(rootDir, 'server', 'src', 'db', 'mysql.ts');
|
||||
const repoPath = path.join(rootDir, 'server', 'src', 'db', 'repository.ts');
|
||||
const indexPath = path.join(rootDir, 'server', 'src', 'index.ts');
|
||||
const apiPath = path.join(rootDir, 'pwuniapp', 'common', 'api.js');
|
||||
const communityPath = path.join(rootDir, 'pwuniapp', 'pages', 'community', 'index.vue');
|
||||
|
||||
const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u2600-\u27BF])/u;
|
||||
expect(emojiRegex.test(fs.readFileSync(mysqlPath, 'utf-8'))).toBe(false);
|
||||
expect(emojiRegex.test(fs.readFileSync(repoPath, 'utf-8'))).toBe(false);
|
||||
expect(emojiRegex.test(fs.readFileSync(indexPath, 'utf-8'))).toBe(false);
|
||||
expect(emojiRegex.test(fs.readFileSync(apiPath, 'utf-8'))).toBe(false);
|
||||
expect(emojiRegex.test(fs.readFileSync(communityPath, 'utf-8'))).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户