fix(core): comprehensive fix for state loss across activity, ticket, workspace, favorites and community

这个提交包含在:
xcbyy
2026-10-13 16:01:19 +08:00
父节点 497fb65359
当前提交 1853e653fb
共有 7 个文件被更改,包括 242 次插入 和 61 次删除

查看文件

@@ -169,9 +169,10 @@ export async function leaveActivity(activityId, userId = 2001) {
/**
* 获取“我的组局”(发起的 + 报名的)
*/
export async function getMyActivities(userId = 1001) {
export async function getMyActivities(userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.get(`/users/${userId}/my-activities`);
const res = await http.get(`/users/${uid}/my-activities`);
if (res) {
return {
created: (res.created || []).map(formatActivityData),
@@ -477,7 +478,13 @@ export async function likePost(id, action, userId) {
* 规范化用户ID,自动兼容历史测试账号映射 (将虚拟陪伴师 101 映射至真实用户 2006)
*/
function normalizeUserId(uid) {
const n = Number(uid);
let target = uid;
if (!target && target !== 0) {
try {
target = uni.getStorageSync('userId');
} catch (_) {}
}
const n = Number(target);
if (n === 101) return 2006;
return (!isNaN(n) && n > 0) ? n : 1001;
}
@@ -952,9 +959,10 @@ export async function updateExpertServiceStatus(expertId = 101, serviceId, statu
/**
* 获取用户收藏的陪玩列表
*/
export async function getFavorites(userId = 1001) {
export async function getFavorites(userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.get(`/favorites?userId=${userId}`);
const res = await http.get(`/favorites?userId=${uid}`);
return res || [];
} catch (err) {
console.warn('[API] 获取收藏列表异常:', err.message);
@@ -965,9 +973,10 @@ export async function getFavorites(userId = 1001) {
/**
* 探测是否已收藏特定陪玩
*/
export async function checkFavorite(expertId, userId = 1001) {
export async function checkFavorite(expertId, userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.get(`/favorites/check?userId=${userId}&expertId=${expertId}`);
const res = await http.get(`/favorites/check?userId=${uid}&expertId=${expertId}`);
return res && res.isFavorite;
} catch (err) {
console.warn('[API] 探测收藏状态异常:', err.message);
@@ -978,9 +987,10 @@ export async function checkFavorite(expertId, userId = 1001) {
/**
* 添加收藏
*/
export async function addFavorite(expertId, userId = 1001) {
export async function addFavorite(expertId, userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.post('/favorites', { userId, expertId });
const res = await http.post('/favorites', { userId: uid, expertId });
return res;
} catch (err) {
console.warn('[API] 添加收藏异常:', err.message);
@@ -991,9 +1001,10 @@ export async function addFavorite(expertId, userId = 1001) {
/**
* 取消收藏
*/
export async function removeFavorite(expertId, userId = 1001) {
export async function removeFavorite(expertId, userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.delete(`/favorites/${expertId}?userId=${userId}`);
const res = await http.delete(`/favorites/${expertId}?userId=${uid}`);
return res;
} catch (err) {
console.warn('[API] 取消收藏异常:', err.message);
@@ -1004,9 +1015,10 @@ export async function removeFavorite(expertId, userId = 1001) {
/**
* 获取分销团队列表 (一级与二级成员)
*/
export async function getDistributionTeam(userId = 1001) {
export async function getDistributionTeam(userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.get(`/distribution/team?userId=${userId}`);
const res = await http.get(`/distribution/team?userId=${uid}`);
return res || { directCount: 0, indirectCount: 0, totalTeamCount: 0, directList: [], indirectList: [] };
} catch (err) {
console.warn('[API] 获取分销团队异常:', err.message);
@@ -1017,9 +1029,10 @@ export async function getDistributionTeam(userId = 1001) {
/**
* 获取分销返佣订单记录
*/
export async function getDistributionRecords(userId = 1001) {
export async function getDistributionRecords(userId) {
const uid = normalizeUserId(userId);
try {
const res = await http.get(`/distribution/records?userId=${userId}`);
const res = await http.get(`/distribution/records?userId=${uid}`);
return res || [];
} catch (err) {
console.warn('[API] 获取分销返佣记录异常:', err.message);

查看文件

@@ -137,12 +137,12 @@
<text class="sec-sub">满员即成局</text>
</view>
<view class="member-list" v-if="activity.participants && activity.participants.length > 0">
<view v-for="(p, index) in activity.participants" :key="p.id" class="member-item" :class="{ 'my-member-item': Number(p.userId) === CURRENT_USER_ID }">
<view v-for="(p, index) in activity.participants" :key="p.id" class="member-item" :class="{ 'my-member-item': Number(p.userId) === currentUserId }">
<image class="member-avatar" :src="p.avatar" mode="aspectFill" />
<view class="member-info">
<view class="member-top-line">
<text class="member-name">{{ p.nickname }}</text>
<text class="my-badge" v-if="Number(p.userId) === CURRENT_USER_ID">我的席位</text>
<text class="my-badge" v-if="Number(p.userId) === currentUserId">我的席位</text>
<text class="member-price-tag" v-if="p.priceAtJoin">
出价: ¥{{ p.priceAtJoin }}
</text>
@@ -158,7 +158,7 @@
<view class="checkin-badge" :class="{ checked: p.checkedIn }">
{{ p.checkedIn ? '已核销到场' : '待现场核销' }}
</view>
<text class="btn-micro-leave btn-active" v-if="Number(p.userId) === CURRENT_USER_ID && !p.checkedIn" @click.stop="handleLeave">
<text class="btn-micro-leave btn-active" v-if="Number(p.userId) === currentUserId && !p.checkedIn" @click.stop="handleLeave">
退席
</text>
</view>
@@ -384,18 +384,26 @@ import {
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
const CURRENT_USER_ID = 1001;
const currentUserId = computed(() => {
try {
return Number(uni.getStorageSync('userId')) || 1001;
} catch (_) {
return 1001;
}
});
const currentActId = ref('1');
const verifyCodeInput = ref('');
const currentThemeKey = ref(getCurrentThemeKey());
const isHost = computed(() => {
if (!activity.value) return false;
return Number(activity.value.creatorId) === CURRENT_USER_ID;
return Number(activity.value.creatorId) === currentUserId.value;
});
const myParticipantInfo = computed(() => {
if (!activity.value || !activity.value.participants) return null;
return activity.value.participants.find(p => Number(p.userId) === CURRENT_USER_ID || Number(p.id) === CURRENT_USER_ID);
const uid = currentUserId.value;
return activity.value.participants.find(p => Number(p.userId) === uid || Number(p.id) === uid);
});
const isJoined = computed(() => !!myParticipantInfo.value);
@@ -421,6 +429,9 @@ onMounted(() => {
onShow(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
if (currentActId.value) {
loadLiveDetail(currentActId.value);
}
});
onUnmounted(() => {
@@ -458,6 +469,7 @@ const loadLiveDetail = async (id) => {
onLoad((query) => {
const targetId = (query && query.id) ? query.id : '1';
currentActId.value = targetId;
loadLiveDetail(targetId);
});
@@ -639,7 +651,7 @@ const handleHostVerify = async () => {
}
try {
uni.showLoading({ title: '正在核销签到...' });
await verifyActivityCheckin(activity.value.id, code, CURRENT_USER_ID);
await verifyActivityCheckin(activity.value.id, code, currentUserId.value);
uni.hideLoading();
verifyCodeInput.value = '';
uni.showToast({ title: '核销成功!搭子已签到', icon: 'success' });
@@ -675,7 +687,7 @@ const handleHostCancel = () => {
if (res.confirm) {
try {
uni.showLoading({ title: '正在解散并全额退款...' });
await cancelActivity(activity.value.id, CURRENT_USER_ID, '局长主动解散组局');
await cancelActivity(activity.value.id, currentUserId.value, '局长主动解散组局');
uni.hideLoading();
uni.showToast({ title: '组局已成功解散', icon: 'success' });
activity.value.status = 'CANCELLED';
@@ -703,7 +715,7 @@ const handleLeave = () => {
if (res.confirm) {
try {
uni.showLoading({ title: '正在办理退席...' });
await leaveActivity(activity.value.id, CURRENT_USER_ID);
await leaveActivity(activity.value.id, currentUserId.value);
uni.hideLoading();
uni.showToast({ title: '已退席,款项已退回钱包', icon: 'success' });
loadLiveDetail(activity.value.id);

查看文件

@@ -121,7 +121,7 @@
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { getActivityDetail, verifyActivityCheckin, getMyActivities, leaveActivity } from '@/common/api.js';
import { encodeCode128B } from '@/common/barcode.js';
import { generateQRCodeMatrix } from '@/common/qrcode.js';
@@ -140,6 +140,14 @@ const isCheckedIn = ref(false);
const currentTime = ref('');
const hasTicket = ref(true);
const currentUserId = computed(() => {
try {
return Number(uni.getStorageSync('userId')) || 1001;
} catch (_) {
return 1001;
}
});
const ticketSn = computed(() => {
const actId = ticketData.value && ticketData.value.id ? ticketData.value.id : '101';
return `TICKET-${actId}-${verifyCode.value}`;
@@ -170,7 +178,9 @@ const updateTime = () => {
currentTime.value = `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
};
onLoad(async (query) => {
let savedQuery = null;
const loadTicketData = async (query = savedQuery) => {
if (query && query.code) {
verifyCode.value = String(query.code);
}
@@ -199,17 +209,18 @@ onLoad(async (query) => {
// 2. 若无传参,真实拉取当前用户的已报名组局列表
try {
const myActs = await getMyActivities(1001);
const uid = currentUserId.value;
const myActs = await getMyActivities(uid);
const joinedList = myActs.joined || [];
if (joinedList.length > 0) {
let targetAct = joinedList.find(act => {
const myP = (act.participants || []).find(p => p.userId === 1001 || p.nickname === '同城局长' || p.verifyCode);
const myP = (act.participants || []).find(p => Number(p.userId) === uid || p.nickname === '同城局长' || p.verifyCode);
return myP && !myP.checkedIn;
}) || joinedList[0];
ticketData.value = targetAct;
if (targetAct.participants && targetAct.participants.length > 0) {
const myP = targetAct.participants.find(p => p.userId === 1001 || p.verifyCode);
const myP = targetAct.participants.find(p => Number(p.userId) === uid || p.verifyCode);
if (myP && myP.verifyCode) {
verifyCode.value = String(myP.verifyCode);
isCheckedIn.value = Boolean(myP.checkedIn);
@@ -235,8 +246,16 @@ onLoad(async (query) => {
}
}
} catch (_) {}
};
onLoad(async (query) => {
savedQuery = query;
await loadTicketData(query);
});
onShow(async () => {
await loadTicketData();
});
onMounted(() => {
updateTime();
@@ -251,7 +270,7 @@ const toggleCheckIn = async () => {
if (!isCheckedIn.value) {
try {
uni.showLoading({ title: '正在核销签到...' });
await verifyActivityCheckin(ticketData.value.id, verifyCode.value, 1001);
await verifyActivityCheckin(ticketData.value.id, verifyCode.value, currentUserId.value);
uni.hideLoading();
isCheckedIn.value = true;
uni.showToast({
@@ -291,7 +310,7 @@ const handleCancelTicket = () => {
try {
uni.showLoading({ title: '正在办理退票...' });
const actId = ticketData.value && ticketData.value.id ? ticketData.value.id : 'act_101';
await leaveActivity(actId, 1001);
await leaveActivity(actId, currentUserId.value);
uni.hideLoading();
uni.showToast({ title: '退票成功,款项已退回钱包', icon: 'success' });
setTimeout(() => {

查看文件

@@ -80,8 +80,14 @@
>
删除
</button>
<button v-else class="join-btn btn-active" @click="handleJoinParty(post)">
{{ post.actionText || '聊一聊' }}
<button
v-else
class="join-btn btn-active"
:class="{ 'btn-applied': post.hasApplied }"
:disabled="post.hasApplied"
@click="handleJoinParty(post)"
>
{{ post.hasApplied ? '已申请' : (post.actionText || '聊一聊') }}
</button>
</view>
</view>
@@ -380,10 +386,18 @@ const loadRemotePosts = async () => {
if (list && list.length > 0) {
let localLikedIds = uni.getStorageSync('COMMUNITY_LIKED_POST_IDS') || [];
if (!Array.isArray(localLikedIds)) localLikedIds = [];
posts.value = list.map(item => ({
...item,
liked: item.liked !== undefined ? item.liked : localLikedIds.includes(String(item.id))
}));
let localAppliedIds = uni.getStorageSync('COMMUNITY_APPLIED_POST_IDS') || [];
if (!Array.isArray(localAppliedIds)) localAppliedIds = [];
posts.value = list.map(item => {
const isApplied = localAppliedIds.includes(String(item.id));
return {
...item,
liked: item.liked !== undefined ? item.liked : localLikedIds.includes(String(item.id)),
hasApplied: isApplied,
actionText: isApplied ? '已申请' : (item.actionText || '加入车队')
};
});
}
} catch (err) {
console.warn('[Community] 获取动态列表失败,保持本地列表:', err.message);
@@ -416,20 +430,29 @@ const feedTabs = ref([
const currentTab = ref('all');
const syncInitialLikedState = (rawPosts) => {
const syncInitialPostStates = (rawPosts) => {
try {
let localLikedIds = uni.getStorageSync('COMMUNITY_LIKED_POST_IDS') || [];
if (!Array.isArray(localLikedIds) || localLikedIds.length === 0) return rawPosts;
return rawPosts.map(p => ({
...p,
liked: localLikedIds.includes(String(p.id)) ? true : p.liked
}));
if (!Array.isArray(localLikedIds)) localLikedIds = [];
let localAppliedIds = uni.getStorageSync('COMMUNITY_APPLIED_POST_IDS') || [];
if (!Array.isArray(localAppliedIds)) localAppliedIds = [];
return rawPosts.map(p => {
const isApplied = localAppliedIds.includes(String(p.id));
return {
...p,
liked: localLikedIds.includes(String(p.id)) ? true : p.liked,
hasApplied: isApplied,
actionText: isApplied ? '已申请' : p.actionText
};
});
} catch (_) {
return rawPosts;
}
};
const syncInitialLikedState = syncInitialPostStates;
const posts = ref(syncInitialLikedState([
const posts = ref(syncInitialPostStates([
{
id: 1,
author: '小甜橙',
@@ -658,6 +681,13 @@ const handleDeletePost = (post) => {
};
const handleJoinParty = (post) => {
if (post.hasApplied) {
uni.showToast({
title: '已提交过约伴申请',
icon: 'none'
});
return;
}
uni.showModal({
title: '搭子互动申请',
content: `确定向【${post.author}】发起同城约伴 / 上车请求?`,
@@ -666,24 +696,33 @@ const handleJoinParty = (post) => {
success: async (res) => {
if (res.confirm) {
uni.showLoading({ title: '正在提交申请...' });
const uid = Number(uni.getStorageSync('userId')) || 1001;
const userInfo = uni.getStorageSync('userInfo') || {};
const applicantName = userInfo.nickname || '搭子玩家';
const applicantAvatar = userInfo.avatar || 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=120';
try {
await applyPostParty(post.id, {
applicantId: 1001,
applicantName: '电竞玩家 (我)',
applicantAvatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=120'
});
uni.hideLoading();
uni.showToast({
title: '申请已送达,等待房主确认!',
icon: 'success'
});
} catch (_) {
uni.hideLoading();
uni.showToast({
title: '申请已送达,等待房主确认!',
icon: 'success'
applicantId: uid,
applicantName,
applicantAvatar
});
} catch (_) {}
post.hasApplied = true;
post.actionText = '已申请';
let localAppliedIds = uni.getStorageSync('COMMUNITY_APPLIED_POST_IDS') || [];
if (!Array.isArray(localAppliedIds)) localAppliedIds = [];
const strId = String(post.id);
if (!localAppliedIds.includes(strId)) {
localAppliedIds.push(strId);
uni.setStorageSync('COMMUNITY_APPLIED_POST_IDS', localAppliedIds);
}
uni.hideLoading();
uni.showToast({
title: '申请已送达,等待房主确认!',
icon: 'success'
});
}
}
});
@@ -1212,6 +1251,13 @@ const submitPublishPost = async () => {
font-weight: 600;
margin: 0;
line-height: 1.5;
&.btn-applied {
background: rgba(148, 163, 184, 0.15);
color: #94A3B8;
border-color: rgba(148, 163, 184, 0.3);
opacity: 0.8;
}
}
}
}
@@ -1769,6 +1815,12 @@ const submitPublishPost = async () => {
background: rgba(234, 88, 12, 0.1);
color: #EA580C;
border-color: rgba(234, 88, 12, 0.3);
&.btn-applied {
background: #F1F5F9;
color: #94A3B8;
border-color: #CBD5E1;
}
}
}

查看文件

@@ -241,7 +241,7 @@
<script setup>
import { ref, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { onLoad, onShow } from '@dcloudio/uni-app';
import SkeletonScreen from '@/components/SkeletonScreen.vue';
import { getCompanionDetail, getExpertReviews, replyOrderReview, submitReport as submitReportApi, checkFavorite, addFavorite as addFavApi, removeFavorite as removeFavApi } from '@/common/api.js';
import { ICONS } from '@/common/icons.js';
@@ -268,10 +268,23 @@ const expert = ref({
});
const selectedServiceId = ref(null);
const isPlayingVoice = ref(false);
let currentExpertTargetId = null;
const refreshFavoriteState = async () => {
if (!currentExpertTargetId) return;
try {
const favStatus = await checkFavorite(currentExpertTargetId);
isFav.value = Boolean(favStatus);
} catch (_) {}
};
onShow(() => {
refreshFavoriteState();
});
const toggleFavorite = async () => {
try {
const targetId = Number(expert.value.id || 101);
const targetId = Number(expert.value.id || currentExpertTargetId || 101);
if (isFav.value) {
await removeFavApi(targetId);
isFav.value = false;
@@ -315,6 +328,7 @@ const handleReplyReview = (rev) => {
onLoad(async (query) => {
const targetId = (query && query.id) ? query.id : '1';
currentExpertTargetId = targetId;
try {
const liveData = await getCompanionDetail(targetId);
if (liveData) {

查看文件

@@ -415,7 +415,7 @@ const expert = ref({
nickname: '认证大神',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=300'
});
const isReceivingOrders = ref(true);
const isReceivingOrders = ref(uni.getStorageSync('EXPERT_RECEIVING_STATUS') !== '0');
const todayIncome = ref('0.00');
const todayOrdersCount = ref(0);
const waitingVerifyCount = ref(0);
@@ -579,6 +579,7 @@ const activeOrders = ref([
const toggleReceivingStatus = () => {
isReceivingOrders.value = !isReceivingOrders.value;
uni.setStorageSync('EXPERT_RECEIVING_STATUS', isReceivingOrders.value ? '1' : '0');
uni.showToast({
title: isReceivingOrders.value ? '已开启在线接单通道!' : '已打烊停止接单',
icon: 'none'
@@ -677,6 +678,7 @@ onShow(() => {
}, 400);
return;
}
isReceivingOrders.value = uni.getStorageSync('EXPERT_RECEIVING_STATUS') !== '0';
loadWorkspaceOrders();
});

查看文件

@@ -999,6 +999,75 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安
expect(emojiRegex.test(fs.readFileSync(communityPath, 'utf-8'))).toBe(false);
});
});
describe('23. 全模块状态持久化与跨页面状态同步健壮性规范验证 (组局/门票/工作台/收藏/搭子)', () => {
it('API 层 normalizeUserId 与收藏/组局方法必须优先支持 Storage 用户ID', () => {
const apiPath = path.join(rootDir, 'pwuniapp', 'common', 'api.js');
const content = fs.readFileSync(apiPath, 'utf-8');
expect(content).toContain("uni.getStorageSync('userId')");
expect(content).toContain('function normalizeUserId');
expect(content).toContain('export async function getFavorites(userId)');
expect(content).toContain('export async function checkFavorite(expertId, userId)');
});
it('组局详情页必须动态响应当前用户并在 onShow 中拉取最新数据', () => {
const actDetailPath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'detail.vue');
const content = fs.readFileSync(actDetailPath, 'utf-8');
expect(content).toContain('currentUserId');
expect(content).toContain('currentActId');
expect(content).toContain('loadLiveDetail(currentActId.value)');
expect(content).not.toContain('const CURRENT_USER_ID = 1001;');
});
it('我的门票页面必须注册 onShow 并在退票与核销时绑定动态用户', () => {
const ticketPath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'my-ticket.vue');
const content = fs.readFileSync(ticketPath, 'utf-8');
expect(content).toContain('onShow');
expect(content).toContain('currentUserId');
expect(content).toContain('loadTicketData()');
expect(content).toContain('leaveActivity(actId, currentUserId.value)');
});
it('大神工作台接单状态必须持久化 EXPERT_RECEIVING_STATUS 并在 onShow 恢复', () => {
const wsPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'workspace.vue');
const content = fs.readFileSync(wsPath, 'utf-8');
expect(content).toContain('EXPERT_RECEIVING_STATUS');
expect(content).toContain("uni.setStorageSync('EXPERT_RECEIVING_STATUS'");
});
it('大神主页必须在 onShow 中刷新当前用户的收藏状态', () => {
const expertDetailPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'detail.vue');
const content = fs.readFileSync(expertDetailPath, 'utf-8');
expect(content).toContain('onShow');
expect(content).toContain('refreshFavoriteState');
expect(content).toContain('currentExpertTargetId');
});
it('友圈页面必须通过 COMMUNITY_APPLIED_POST_IDS 持久化申请上车状态并防重', () => {
const communityPath = path.join(rootDir, 'pwuniapp', 'pages', 'community', 'index.vue');
const content = fs.readFileSync(communityPath, 'utf-8');
expect(content).toContain('COMMUNITY_APPLIED_POST_IDS');
expect(content).toContain('btn-applied');
expect(content).toContain('syncInitialPostStates');
});
it('所有状态持久化修复代码与测试严禁包含任何系统 Emoji 违规字符', () => {
const actDetailPath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'detail.vue');
const ticketPath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'my-ticket.vue');
const wsPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'workspace.vue');
const expertDetailPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'detail.vue');
const communityPath = path.join(rootDir, 'pwuniapp', 'pages', 'community', 'index.vue');
const apiPath = path.join(rootDir, 'pwuniapp', 'common', 'api.js');
const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u2600-\u27BF])/u;
expect(emojiRegex.test(fs.readFileSync(actDetailPath, 'utf-8'))).toBe(false);
expect(emojiRegex.test(fs.readFileSync(ticketPath, 'utf-8'))).toBe(false);
expect(emojiRegex.test(fs.readFileSync(wsPath, 'utf-8'))).toBe(false);
expect(emojiRegex.test(fs.readFileSync(expertDetailPath, 'utf-8'))).toBe(false);
expect(emojiRegex.test(fs.readFileSync(communityPath, 'utf-8'))).toBe(false);
expect(emojiRegex.test(fs.readFileSync(apiPath, 'utf-8'))).toBe(false);
});
});
});