This commit is contained in:
pa
2026-03-11 22:03:57 +09:00
parent bf9b66bdf4
commit 884744cb30
35 changed files with 892 additions and 515 deletions

View File

@@ -0,0 +1,128 @@
import { beforeEach, describe, expect, test, vi } from 'vitest';
const mocks = vi.hoisted(() => ({
useAppearanceSettingsStore: vi.fn()
}));
vi.mock('../../stores', () => ({
useAppearanceSettingsStore: (...args) =>
mocks.useAppearanceSettingsStore(...args)
}));
import { formatDateFilter } from '../dateCoordinator';
describe('dateCoordinator.formatDateFilter', () => {
beforeEach(() => {
vi.restoreAllMocks();
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: false,
dtHour12: false,
currentCulture: 'en-gb'
});
});
test('returns "-" for empty and invalid input', () => {
expect(formatDateFilter('', 'long')).toBe('-');
expect(formatDateFilter(null, 'long')).toBe('-');
expect(formatDateFilter(undefined, 'long')).toBe('-');
expect(formatDateFilter('invalid-date', 'long')).toBe('-');
});
test('uses ISO long format when dtIsoFormat is enabled', () => {
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: true,
dtHour12: false,
currentCulture: 'ja-jp'
});
const result = formatDateFilter('2024-01-02T03:04:05Z', 'long');
expect(result).toMatch(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
});
test('keeps culture unchanged when underscore is not at index 4', () => {
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: false,
dtHour12: false,
currentCulture: 'en_us'
});
const localeSpy = vi.spyOn(Date.prototype, 'toLocaleDateString');
localeSpy.mockReturnValue('01/02/2024');
formatDateFilter('2024-01-02T03:04:05Z', 'date');
expect(localeSpy).toHaveBeenCalledWith(
'en_us',
expect.objectContaining({
year: 'numeric'
})
);
});
test('truncates culture when underscore is at index 4', () => {
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: false,
dtHour12: false,
currentCulture: 'abcd_ef'
});
const localeSpy = vi.spyOn(Date.prototype, 'toLocaleDateString');
localeSpy.mockReturnValue('01/02/2024');
formatDateFilter('2024-01-02T03:04:05Z', 'date');
expect(localeSpy).toHaveBeenCalledWith(
'abcd',
expect.objectContaining({
year: 'numeric'
})
);
});
test('falls back to en-gb when currentCulture is empty', () => {
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: false,
dtHour12: false,
currentCulture: ''
});
const localeSpy = vi.spyOn(Date.prototype, 'toLocaleDateString');
localeSpy.mockReturnValue('02/01/2024');
formatDateFilter('2024-01-02T03:04:05Z', 'date');
expect(localeSpy).toHaveBeenCalledWith(
'en-gb',
expect.objectContaining({
year: 'numeric'
})
);
});
test('uses hourCycle h12 and lowercases AM/PM in short format', () => {
mocks.useAppearanceSettingsStore.mockReturnValue({
dtIsoFormat: false,
dtHour12: true,
currentCulture: 'en-us'
});
const localeSpy = vi.spyOn(Date.prototype, 'toLocaleDateString');
localeSpy.mockReturnValue('01/02, 10:30 PM');
const result = formatDateFilter('2024-01-02T22:30:00Z', 'short');
expect(localeSpy).toHaveBeenCalledWith(
'en-us',
expect.objectContaining({
hourCycle: 'h12'
})
);
expect(result).toContain('pm');
expect(result).not.toContain('PM');
});
test('returns "-" and warns when format is unknown', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const result = formatDateFilter('2024-01-02T03:04:05Z', 'unknown');
expect(result).toBe('-');
expect(warnSpy).toHaveBeenCalledWith('Unknown date format: unknown');
});
});

View File

@@ -54,7 +54,6 @@ export async function runLogoutFlow() {
*/
export function runLoginSuccessFlow(json) {
const updateLoopStore = useUpdateLoopStore();
const userStore = useUserStore();
updateLoopStore.setNextCurrentUserRefresh(420); // 7mins
applyCurrentUser(json);

View File

@@ -185,7 +185,7 @@ export async function getAvatarHistory() {
}
applyAvatar(avatar);
}
avatarStore.avatarHistory = historyArray;
avatarStore.setAvatarHistory(historyArray);
}
/**
@@ -530,8 +530,8 @@ export async function checkAvatarCacheRemote(fileId, ownerUserId) {
if (advancedSettingsStore.avatarRemoteDatabase) {
try {
toast.dismiss(avatarStore.loadingToastId);
avatarStore.loadingToastId = toast.loading(
t('message.avatar_lookup.loading')
avatarStore.setLoadingToastId(
toast.loading(t('message.avatar_lookup.loading'))
);
const avatarId = await lookupAvatarByImageFileId(
ownerUserId,

View File

@@ -113,8 +113,8 @@ export function handleFavoriteAtDelete(ref) {
favoriteStore.cachedFavoritesByObjectId.delete(ref.favoriteId);
favoriteStore.state.favoriteObjects.delete(ref.favoriteId);
friendStore.localFavoriteFriends.delete(ref.favoriteId);
favoriteStore.favoritesSortOrder = favoriteStore.favoritesSortOrder.filter(
(id) => id !== ref.favoriteId
favoriteStore.setFavoritesSortOrder(
favoriteStore.favoritesSortOrder.filter((id) => id !== ref.favoriteId)
);
runUpdateFriendFlow(ref.favoriteId);
@@ -389,14 +389,14 @@ export function refreshFavorites() {
if (favoriteStore.isFavoriteLoading) {
return;
}
favoriteStore.isFavoriteLoading = true;
favoriteStore.setIsFavoriteLoading(true);
queryRequest
.fetch('favoriteLimits')
.then((args) => {
favoriteStore.favoriteLimits = {
favoriteStore.setFavoriteLimits({
...favoriteStore.favoriteLimits,
...args.json
};
});
})
.catch((err) => {
console.error(err);
@@ -430,12 +430,12 @@ export function refreshFavorites() {
}
}
}
favoriteStore.favoritesSortOrder = newFavoriteSortOrder;
favoriteStore.setFavoritesSortOrder(newFavoriteSortOrder);
}
refreshFavoriteItems();
favoriteStore.refreshFavoriteGroups();
friendStore.updateLocalFavoriteFriends();
favoriteStore.isFavoriteLoading = false;
favoriteStore.setIsFavoriteLoading(false);
watchState.isFavoritesLoaded = true;
favoriteStore.countFavoriteGroups();
}
@@ -445,7 +445,7 @@ export function refreshFavorites() {
/**
*
* @param {string} tag
* @returns {void}
* @returns {Promise<void>}
*/
export async function refreshFavoriteAvatars(tag) {
const params = {

View File

@@ -5,7 +5,6 @@ import { friendRequest, userRequest } from '../api';
import { getNameColour } from '../shared/utils';
import { handleFavoriteDelete } from './favoriteCoordinator';
import { useAppearanceSettingsStore } from '../stores/settings/appearance';
import { useFavoriteStore } from '../stores/favorite';
import { useFriendStore } from '../stores/friend';
import { useModalStore } from '../stores/modal';
import { useNotificationStore } from '../stores/notification';
@@ -342,7 +341,6 @@ export function runDeleteFriendshipFlow(
const userStore = useUserStore();
const notificationStore = useNotificationStore();
const sharedFeedStore = useSharedFeedStore();
const favoriteStore = useFavoriteStore();
const uiStore = useUiStore();
const appearanceSettingsStore = useAppearanceSettingsStore();

View File

@@ -17,7 +17,6 @@ import configRepository from '../services/config';
*/
export async function runRefreshFriendsListFlow() {
const updateLoopStore = useUpdateLoopStore();
const userStore = useUserStore();
const friendStore = useFriendStore();
// If we just got user less then 2 min before code call, don't call it again
@@ -38,7 +37,7 @@ export async function runInitFriendsListFlow(t) {
const authStore = useAuthStore();
const userId = userStore.currentUser.id;
friendStore.isRefreshFriendsLoading = true;
friendStore.setIsRefreshFriendsLoading(true);
watchState.isFriendsLoaded = false;
friendStore.resetFriendLog();

View File

@@ -33,10 +33,8 @@ export async function runGameRunningChangedFlow(isGameRunning) {
const userStore = useUserStore();
const instanceStore = useInstanceStore();
const updateLoopStore = useUpdateLoopStore();
const locationStore = useLocationStore();
const gameLogStore = useGameLogStore();
const vrStore = useVrStore();
const avatarStore = useAvatarStore();
const gameStore = useGameStore();
if (isGameRunning) {

View File

@@ -304,7 +304,7 @@ export function addGameLogEntry(gameLog, location) {
if (gameLogStore.lastVideoUrl === gameLog.videoUrl) {
break;
}
gameLogStore.lastVideoUrl = gameLog.videoUrl;
gameLogStore.setLastVideoUrl(gameLog.videoUrl);
gameLogStore.addGameLogVideo(gameLog, location, userId);
break;
case 'video-sync':
@@ -321,7 +321,7 @@ export function addGameLogEntry(gameLog, location) {
) {
break;
}
gameLogStore.lastResourceloadUrl = gameLog.resourceUrl;
gameLogStore.setLastResourceloadUrl(gameLog.resourceUrl);
entry = createResourceLoadEntry(
gameLog.type,
gameLog.dt,

View File

@@ -57,7 +57,6 @@ function applyGroupLanguage(ref) {
*/
export function applyGroup(json) {
const groupStore = useGroupStore();
const userStore = useUserStore();
let ref = groupStore.cachedGroups.get(json.id);
sanitizeEntityJson(json, ['rules', 'name', 'description']);
if (typeof ref === 'undefined') {
@@ -629,7 +628,7 @@ export async function loadCurrentUserGroups(userId, groups) {
await Promise.allSettled(promises);
}
groupStore.currentUserGroupsInit = true;
groupStore.setCurrentUserGroupsInit(true);
getCurrentUserGroups();
}
@@ -691,7 +690,7 @@ export async function updateInGameGroupOrder() {
const groupStore = useGroupStore();
const gameStore = useGameStore();
const userStore = useUserStore();
groupStore.inGameGroupOrder = [];
groupStore.setInGameGroupOrder([]);
try {
const json = await gameStore.getVRChatRegistryKey(
`VRC_GROUP_ORDER_${userStore.currentUser.id}`
@@ -699,7 +698,7 @@ export async function updateInGameGroupOrder() {
if (!json) {
return;
}
groupStore.inGameGroupOrder = JSON.parse(json);
groupStore.setInGameGroupOrder(JSON.parse(json));
} catch (err) {
console.error(err);
}
@@ -925,7 +924,7 @@ export function handleGroupMember(args) {
export async function handleGroupUserInstances(args) {
const groupStore = useGroupStore();
const instanceStore = useInstanceStore();
groupStore.groupInstances = [];
groupStore.setGroupInstances([]);
for (const json of args.json.instances) {
if (args.json.fetchedAt) {
// tack on fetchedAt

View File

@@ -669,7 +669,7 @@ export function handleConfig(args) {
if (!languages) {
return;
}
userStore.subsetOfLanguages = languages;
userStore.setSubsetOfLanguages(languages);
const data = [];
for (const key in languages) {
const value = languages[key];
@@ -678,7 +678,7 @@ export function handleConfig(args) {
value
});
}
userStore.languageDialog.languages = data;
userStore.setLanguageDialogLanguages(data);
}
/**

View File

@@ -1,7 +1,6 @@
import { getGroupName, getWorldName, parseLocation } from '../shared/utils';
import { AppDebug } from '../services/appConfig';
import { database } from '../services/database';
import { useAvatarStore } from '../stores/avatar';
import { getAvatarName } from './avatarCoordinator';
import { useFeedStore } from '../stores/feed';
import { useFriendStore } from '../stores/friend';
@@ -35,7 +34,6 @@ export async function runHandleUserUpdateFlow(
const feedStore = useFeedStore();
const notificationStore = useNotificationStore();
const sharedFeedStore = useSharedFeedStore();
const avatarStore = useAvatarStore();
const generalSettingsStore = useGeneralSettingsStore();
const { state, userDialog, applyUserDialogLocation, checkNote } = userStore;

View File

@@ -4,11 +4,8 @@ import {
updateUserCurrentStatus
} from './friendRelationshipCoordinator';
import { useAuthStore } from '../stores/auth';
import { useAvatarStore } from '../stores/avatar';
import { addAvatarToHistory, addAvatarWearTime } from './avatarCoordinator';
import { useFriendStore } from '../stores/friend';
import { useGameStore } from '../stores/game';
import { useGroupStore } from '../stores/group';
import { applyPresenceGroups } from './groupCoordinator';
import { useInstanceStore } from '../stores/instance';
import { useUserStore } from '../stores/user';
@@ -26,7 +23,6 @@ export function runAvatarSwapFlow(
{ json, ref, isLoggedIn },
{ now = Date.now } = {}
) {
const avatarStore = useAvatarStore();
const gameStore = useGameStore();
if (!isLoggedIn) {
@@ -56,7 +52,7 @@ export function runFirstLoginFlow(ref, { now = Date.now } = {}) {
ref.$previousAvatarSwapTime = now();
}
userStore.cachedUsers.clear(); // clear before running applyUser
userStore.currentUser = ref;
userStore.setCurrentUser(ref);
authStore.loginComplete();
}
@@ -65,9 +61,7 @@ export function runFirstLoginFlow(ref, { now = Date.now } = {}) {
* @param {object} ref Current user state reference.
*/
export function runPostApplySyncFlow(ref) {
const groupStore = useGroupStore();
const instanceStore = useInstanceStore();
const friendStore = useFriendStore();
applyPresenceGroups(ref);
instanceStore.applyQueuedInstance(ref.queuedInstance);

View File

@@ -3,7 +3,6 @@ import { toast } from 'vue-sonner';
import { i18n } from '../plugins/i18n';
import {
checkVRChatCache,
createDefaultWorldRef,
evictMapCache,
getAvailablePlatforms,