mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-03 21:36:06 +02:00
merge group api request
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
_entityCacheInternals,
|
||||
fetchWithEntityPolicy,
|
||||
patchAndRefetchActiveQuery,
|
||||
patchQueryDataWithRecency
|
||||
} from '../entityCache';
|
||||
import { queryClient } from '../client';
|
||||
|
||||
describe('entity query cache helpers', () => {
|
||||
beforeEach(() => {
|
||||
queryClient.clear();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
test('reports cache hit for fresh data', async () => {
|
||||
const queryKey = ['user', 'usr_1'];
|
||||
let callCount = 0;
|
||||
|
||||
const policy = {
|
||||
staleTime: 20000,
|
||||
gcTime: 90000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
};
|
||||
|
||||
const queryFn = vi.fn(async () => {
|
||||
callCount++;
|
||||
return {
|
||||
json: { id: 'usr_1', updated_at: '2026-01-01T00:00:00.000Z' },
|
||||
params: { userId: 'usr_1' },
|
||||
ref: { id: 'usr_1', updated_at: '2026-01-01T00:00:00.000Z' }
|
||||
};
|
||||
});
|
||||
|
||||
const first = await fetchWithEntityPolicy({ queryKey, policy, queryFn });
|
||||
const second = await fetchWithEntityPolicy({ queryKey, policy, queryFn });
|
||||
|
||||
expect(first.cache).toBe(false);
|
||||
expect(second.cache).toBe(true);
|
||||
expect(callCount).toBe(1);
|
||||
});
|
||||
|
||||
test('always refetches when staleTime is zero (instance strategy)', async () => {
|
||||
const queryKey = ['instance', 'wrld_1', '12345'];
|
||||
let callCount = 0;
|
||||
|
||||
const policy = {
|
||||
staleTime: 0,
|
||||
gcTime: 10000,
|
||||
retry: 0,
|
||||
refetchOnWindowFocus: false
|
||||
};
|
||||
|
||||
const queryFn = vi.fn(async () => {
|
||||
callCount++;
|
||||
return {
|
||||
json: {
|
||||
id: 'wrld_1:12345',
|
||||
$fetchedAt: new Date().toJSON()
|
||||
},
|
||||
params: { worldId: 'wrld_1', instanceId: '12345' },
|
||||
ref: {
|
||||
id: 'wrld_1:12345',
|
||||
$fetchedAt: new Date().toJSON()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
await fetchWithEntityPolicy({ queryKey, policy, queryFn });
|
||||
await fetchWithEntityPolicy({ queryKey, policy, queryFn });
|
||||
|
||||
expect(callCount).toBe(2);
|
||||
});
|
||||
|
||||
test('does not overwrite newer data with older payload', () => {
|
||||
const queryKey = ['world', 'wrld_1'];
|
||||
|
||||
patchQueryDataWithRecency({
|
||||
queryKey,
|
||||
nextData: {
|
||||
ref: { id: 'wrld_1', updated_at: '2026-01-01T00:00:00.000Z' }
|
||||
}
|
||||
});
|
||||
|
||||
patchQueryDataWithRecency({
|
||||
queryKey,
|
||||
nextData: {
|
||||
ref: { id: 'wrld_1', updated_at: '2025-01-01T00:00:00.000Z' }
|
||||
}
|
||||
});
|
||||
|
||||
const cached = queryClient.getQueryData(queryKey);
|
||||
expect(cached.ref.updated_at).toBe('2026-01-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
test('patch and refetch invalidates only active queries for that key', async () => {
|
||||
const invalidateSpy = vi
|
||||
.spyOn(queryClient, 'invalidateQueries')
|
||||
.mockResolvedValue();
|
||||
|
||||
const queryKey = ['avatar', 'avtr_1'];
|
||||
await patchAndRefetchActiveQuery({
|
||||
queryKey,
|
||||
nextData: {
|
||||
ref: { id: 'avtr_1', updated_at: '2026-01-01T00:00:00.000Z' }
|
||||
}
|
||||
});
|
||||
|
||||
expect(invalidateSpy).toHaveBeenCalledWith({
|
||||
queryKey,
|
||||
exact: true,
|
||||
refetchType: 'active'
|
||||
});
|
||||
});
|
||||
|
||||
test('internal recency guard prefers same-or-newer timestamps', () => {
|
||||
const newer = {
|
||||
ref: { id: 'usr_1', updated_at: '2026-02-01T00:00:00.000Z' }
|
||||
};
|
||||
const older = {
|
||||
ref: { id: 'usr_1', updated_at: '2026-01-01T00:00:00.000Z' }
|
||||
};
|
||||
|
||||
expect(_entityCacheInternals.shouldReplaceCurrent(older, newer)).toBe(
|
||||
true
|
||||
);
|
||||
expect(_entityCacheInternals.shouldReplaceCurrent(newer, older)).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { queryKeys } from '../keys';
|
||||
|
||||
describe('query key shapes', () => {
|
||||
test('favorite world keys include owner and tag dimensions', () => {
|
||||
const a = queryKeys.favoriteWorlds({
|
||||
n: 100,
|
||||
offset: 0,
|
||||
ownerId: 'usr_1',
|
||||
userId: 'usr_1',
|
||||
tag: 'worlds1'
|
||||
});
|
||||
const b = queryKeys.favoriteWorlds({
|
||||
n: 100,
|
||||
offset: 0,
|
||||
ownerId: 'usr_2',
|
||||
userId: 'usr_2',
|
||||
tag: 'worlds1'
|
||||
});
|
||||
|
||||
expect(a).not.toEqual(b);
|
||||
});
|
||||
|
||||
test('world list keys include query option discriminator', () => {
|
||||
const base = {
|
||||
userId: 'usr_me',
|
||||
n: 50,
|
||||
offset: 0,
|
||||
sort: 'updated',
|
||||
order: 'descending',
|
||||
user: 'me',
|
||||
releaseStatus: 'all'
|
||||
};
|
||||
|
||||
const defaultKey = queryKeys.worldsByUser(base);
|
||||
const featuredKey = queryKeys.worldsByUser({
|
||||
...base,
|
||||
option: 'featured'
|
||||
});
|
||||
|
||||
expect(defaultKey).not.toEqual(featuredKey);
|
||||
});
|
||||
|
||||
test('group member list keys include sort and role dimensions', () => {
|
||||
const everyone = queryKeys.groupMembers({
|
||||
groupId: 'grp_1',
|
||||
n: 100,
|
||||
offset: 0,
|
||||
sort: 'joinedAt:desc',
|
||||
roleId: ''
|
||||
});
|
||||
const roleScoped = queryKeys.groupMembers({
|
||||
groupId: 'grp_1',
|
||||
n: 100,
|
||||
offset: 0,
|
||||
sort: 'joinedAt:desc',
|
||||
roleId: 'grol_1'
|
||||
});
|
||||
|
||||
expect(everyone).not.toEqual(roleScoped);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import {
|
||||
entityQueryPolicies,
|
||||
getEntityQueryPolicy,
|
||||
toQueryOptions
|
||||
} from '../policies';
|
||||
|
||||
describe('query policy configuration', () => {
|
||||
test('matches the finalized cache strategy', () => {
|
||||
expect(entityQueryPolicies.user).toMatchObject({
|
||||
staleTime: 20000,
|
||||
gcTime: 90000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.avatar).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.world).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.group).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.groupCollection).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.worldCollection).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.instance).toMatchObject({
|
||||
staleTime: 0,
|
||||
gcTime: 10000,
|
||||
retry: 0,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.friendList).toMatchObject({
|
||||
staleTime: 20000,
|
||||
gcTime: 90000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.favoriteCollection).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.galleryCollection).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.inventoryCollection).toMatchObject({
|
||||
staleTime: 20000,
|
||||
gcTime: 120000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
|
||||
expect(entityQueryPolicies.fileObject).toMatchObject({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
});
|
||||
|
||||
test('exposes entity policy lookup', () => {
|
||||
expect(getEntityQueryPolicy('user')).toBe(entityQueryPolicies.user);
|
||||
expect(getEntityQueryPolicy('avatar')).toBe(entityQueryPolicies.avatar);
|
||||
expect(getEntityQueryPolicy('world')).toBe(entityQueryPolicies.world);
|
||||
expect(getEntityQueryPolicy('group')).toBe(entityQueryPolicies.group);
|
||||
expect(getEntityQueryPolicy('groupCollection')).toBe(
|
||||
entityQueryPolicies.groupCollection
|
||||
);
|
||||
expect(getEntityQueryPolicy('worldCollection')).toBe(
|
||||
entityQueryPolicies.worldCollection
|
||||
);
|
||||
expect(getEntityQueryPolicy('instance')).toBe(
|
||||
entityQueryPolicies.instance
|
||||
);
|
||||
expect(getEntityQueryPolicy('friendList')).toBe(
|
||||
entityQueryPolicies.friendList
|
||||
);
|
||||
expect(getEntityQueryPolicy('favoriteCollection')).toBe(
|
||||
entityQueryPolicies.favoriteCollection
|
||||
);
|
||||
expect(getEntityQueryPolicy('galleryCollection')).toBe(
|
||||
entityQueryPolicies.galleryCollection
|
||||
);
|
||||
expect(getEntityQueryPolicy('inventoryCollection')).toBe(
|
||||
entityQueryPolicies.inventoryCollection
|
||||
);
|
||||
expect(getEntityQueryPolicy('fileObject')).toBe(
|
||||
entityQueryPolicies.fileObject
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizes policy values to query options', () => {
|
||||
const options = toQueryOptions(entityQueryPolicies.group);
|
||||
|
||||
expect(options).toEqual({
|
||||
staleTime: 60000,
|
||||
gcTime: 300000,
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user