mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-10-06 22:00:49 +08:00
feat: 隐藏设置里的防撤回入口,历史开启强制收敛为 false
This commit is contained in:
@@ -174,6 +174,12 @@ export function loadSettings(): AppSettings {
|
|||||||
if (cache.dbRoot) {
|
if (cache.dbRoot) {
|
||||||
cache.dbRoot = redirectLegacyWeChatFilesToXwechat(cache.dbRoot)
|
cache.dbRoot = redirectLegacyWeChatFilesToXwechat(cache.dbRoot)
|
||||||
}
|
}
|
||||||
|
// 防撤回已下线(设置入口已隐藏):历史版本可能把它持久化为 true。
|
||||||
|
// 这里强制收敛为 false 并回写磁盘,确保旧的撤回监听与撤回日志不会继续运行。
|
||||||
|
if (cache.recallProtectionEnabled) {
|
||||||
|
cache.recallProtectionEnabled = false
|
||||||
|
saveSettings(cache)
|
||||||
|
}
|
||||||
return cache
|
return cache
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -184,7 +190,9 @@ export function loadSettings(): AppSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function saveSettings(next: AppSettings): AppSettings {
|
export function saveSettings(next: AppSettings): AppSettings {
|
||||||
cache = { ...next }
|
// 防撤回已下线:所有写入路径(含 settings:set 补丁)统一收敛为 false,
|
||||||
|
// 避免遗留入口或旧版本把它重新打开。
|
||||||
|
cache = { ...next, recallProtectionEnabled: false }
|
||||||
try {
|
try {
|
||||||
ensureDir()
|
ensureDir()
|
||||||
fs.writeJsonSync(SETTINGS_FILE, cache, { spaces: 2 })
|
fs.writeJsonSync(SETTINGS_FILE, cache, { spaces: 2 })
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ export const SETTINGS_NAVIGATION: SettingsNavigationGroup[] = [
|
|||||||
{
|
{
|
||||||
label: '应用',
|
label: '应用',
|
||||||
items: [
|
items: [
|
||||||
{ id: 'recall-protection', label: '防撤回' },
|
// “防撤回”已下线,不再在设置里暴露;保留 category/render case 以兼容已有页面状态。
|
||||||
|
// { id: 'recall-protection', label: '防撤回' },
|
||||||
{ id: 'appearance', label: '外观与行为' },
|
{ id: 'appearance', label: '外观与行为' },
|
||||||
{ id: 'advanced', label: '高级' },
|
{ id: 'advanced', label: '高级' },
|
||||||
{ id: 'about', label: '关于' }
|
{ id: 'about', label: '关于' }
|
||||||
@@ -48,5 +49,6 @@ export const SETTINGS_CATEGORY_LABELS = {
|
|||||||
SETTINGS_NAVIGATION.flatMap((group) => group.items.map((item) => [item.id, item.label]))
|
SETTINGS_NAVIGATION.flatMap((group) => group.items.map((item) => [item.id, item.label]))
|
||||||
),
|
),
|
||||||
'personal-wechat-send': '微信发送',
|
'personal-wechat-send': '微信发送',
|
||||||
'storage-export': '存储与导出'
|
'storage-export': '存储与导出',
|
||||||
|
'recall-protection': '防撤回'
|
||||||
} as Record<SettingsCategoryId, string>
|
} as Record<SettingsCategoryId, string>
|
||||||
|
|||||||
@@ -499,11 +499,8 @@ test('SETTINGS-02 basic settings controls fit the default desktop window and kee
|
|||||||
await debugSwitch.click()
|
await debugSwitch.click()
|
||||||
await expect(debugSwitch).toBeChecked()
|
await expect(debugSwitch).toBeChecked()
|
||||||
|
|
||||||
await fixture.page.getByRole('button', { name: '防撤回' }).click()
|
// 防撤回已下线:设置导航不再暴露该入口(与「存储与导出」同一处理方式)。
|
||||||
const recallSwitch = fixture.page.getByRole('switch', { name: '开启防撤回' })
|
await expect(fixture.page.getByRole('button', { name: '防撤回' })).toHaveCount(0)
|
||||||
await expect(recallSwitch).toBeVisible()
|
|
||||||
await recallSwitch.click()
|
|
||||||
await expect(recallSwitch).toBeChecked()
|
|
||||||
|
|
||||||
await fixture.page.getByRole('button', { name: '关于' }).click()
|
await fixture.page.getByRole('button', { name: '关于' }).click()
|
||||||
await expect(fixture.page.getByRole('button', { name: '检查更新' })).toBeVisible()
|
await expect(fixture.page.getByRole('button', { name: '检查更新' })).toBeVisible()
|
||||||
|
|||||||
@@ -661,36 +661,8 @@ test('SETTINGS-03 database key controls visual @visual', async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
for (const appearanceTheme of ['light', 'dark'] as const) {
|
// SETTINGS-08(防撤回页 light/dark 视觉)已移除:该设置入口已下线,
|
||||||
test(`SETTINGS-08 recall protection ${appearanceTheme} visual @visual`, async () => {
|
// 页面不再可达,对应的 settings-recall-protection-{light,dark}.png 基线同步删除。
|
||||||
const fixture = await launchTestApp({ now: visualNow, appearanceTheme })
|
|
||||||
const pageErrors: Error[] = []
|
|
||||||
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
|
||||||
try {
|
|
||||||
await fixture.page
|
|
||||||
.getByRole('navigation', { name: '一级导航' })
|
|
||||||
.getByRole('button', { name: '设置' })
|
|
||||||
.click()
|
|
||||||
await fixture.page.getByRole('button', { name: '防撤回' }).click()
|
|
||||||
await expect(fixture.page.getByRole('switch', { name: '开启防撤回' })).toBeVisible()
|
|
||||||
await expect(fixture.page.locator('html')).toHaveAttribute('data-theme', appearanceTheme)
|
|
||||||
expect(
|
|
||||||
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
|
||||||
).toBe(true)
|
|
||||||
expect(pageErrors).toEqual([])
|
|
||||||
await clearScreenshotFocus(fixture.page)
|
|
||||||
await expect(fixture.page).toHaveScreenshot(
|
|
||||||
`settings-recall-protection-${appearanceTheme}.png`,
|
|
||||||
{
|
|
||||||
animations: 'disabled',
|
|
||||||
caret: 'hide'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
await fixture.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const appearanceTheme of ['light', 'dark'] as const) {
|
for (const appearanceTheme of ['light', 'dark'] as const) {
|
||||||
test(`SETTINGS-04 image decryption controls ${appearanceTheme} visual @visual`, async () => {
|
test(`SETTINGS-04 image decryption controls ${appearanceTheme} visual @visual`, async () => {
|
||||||
|
|||||||
@@ -22,4 +22,11 @@ describe('settings navigation', () => {
|
|||||||
)
|
)
|
||||||
expect(SETTINGS_CATEGORY_LABELS['storage-export']).toBe('存储与导出')
|
expect(SETTINGS_CATEGORY_LABELS['storage-export']).toBe('存储与导出')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('hides recall protection from visible navigation', () => {
|
||||||
|
expect(SETTINGS_NAVIGATION.flatMap((group) => group.items)).not.toEqual(
|
||||||
|
expect.arrayContaining([{ id: 'recall-protection', label: '防撤回' }])
|
||||||
|
)
|
||||||
|
expect(SETTINGS_CATEGORY_LABELS['recall-protection']).toBe('防撤回')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { mkdtempSync, readFileSync, writeFileSync } from 'fs'
|
||||||
|
import { tmpdir } from 'os'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { afterAll, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
|
vi.mock('electron', () => ({ app: { getPath: () => '/tmp/tracememo-settings-test-user-data' } }))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* settings-store 在模块加载时确定 settings.json 路径并缓存设置对象,
|
||||||
|
* 所以每个用例都要用独立的目录 + 重新加载模块。
|
||||||
|
*/
|
||||||
|
async function importStore(directory: string): Promise<
|
||||||
|
typeof import('../../src/main/services/settings-store')
|
||||||
|
> {
|
||||||
|
process.env.WE_SETTINGS_DIR = directory
|
||||||
|
vi.resetModules()
|
||||||
|
return import('../../src/main/services/settings-store')
|
||||||
|
}
|
||||||
|
|
||||||
|
function readSettingsFile(directory: string): Record<string, unknown> {
|
||||||
|
return JSON.parse(readFileSync(join(directory, 'settings.json'), 'utf8')) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDirectory(): string {
|
||||||
|
return mkdtempSync(join(tmpdir(), 'tracememo-settings-recall-'))
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('recall protection retirement migration', () => {
|
||||||
|
afterAll(() => {
|
||||||
|
delete process.env.WE_SETTINGS_DIR
|
||||||
|
})
|
||||||
|
|
||||||
|
it('forces a previously enabled recall protection back to false on disk', async () => {
|
||||||
|
const directory = createDirectory()
|
||||||
|
writeFileSync(
|
||||||
|
join(directory, 'settings.json'),
|
||||||
|
JSON.stringify({ recallProtectionEnabled: true }),
|
||||||
|
'utf8'
|
||||||
|
)
|
||||||
|
|
||||||
|
const store = await importStore(directory)
|
||||||
|
|
||||||
|
expect(store.loadSettings().recallProtectionEnabled).toBe(false)
|
||||||
|
expect(readSettingsFile(directory).recallProtectionEnabled).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps recall protection off for every write path', async () => {
|
||||||
|
const directory = createDirectory()
|
||||||
|
const store = await importStore(directory)
|
||||||
|
|
||||||
|
expect(store.updateSettings({ recallProtectionEnabled: true }).recallProtectionEnabled).toBe(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
expect(store.loadSettings().recallProtectionEnabled).toBe(false)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
store.saveSettings({ ...store.loadSettings(), recallProtectionEnabled: true })
|
||||||
|
.recallProtectionEnabled
|
||||||
|
).toBe(false)
|
||||||
|
expect(readSettingsFile(directory).recallProtectionEnabled).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('defaults recall protection to false without a settings file', async () => {
|
||||||
|
const store = await importStore(createDirectory())
|
||||||
|
|
||||||
|
expect(store.loadSettings().recallProtectionEnabled).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user