test: fix most e2e tests

This commit is contained in:
2026-06-11 10:21:28 +02:00
parent 1671a04f03
commit b630bacdc6
9 changed files with 230 additions and 36 deletions

View File

@@ -79,4 +79,38 @@ describe('user avatar sync helpers', () => {
updatedAt: 100
})).toBe(false);
});
it('requests data when only the remote profile text is newer and no avatar exists', () => {
const existingUser = createUser({
displayName: 'Alice',
profileUpdatedAt: 100
});
expect(shouldRequestAvatarData(existingUser, {
avatarUpdatedAt: 0,
profileUpdatedAt: 200
})).toBe(true);
});
it('does not request profile data when the local profile is the same or newer', () => {
const existingUser = createUser({ profileUpdatedAt: 200 });
expect(shouldRequestAvatarData(existingUser, {
avatarUpdatedAt: 0,
profileUpdatedAt: 200
})).toBe(false);
});
it('applies profile-only transfers when the remote profile is newer', () => {
const existingUser = createUser({
displayName: 'Alice',
profileUpdatedAt: 100
});
expect(shouldApplyAvatarTransfer(existingUser, {
hash: undefined,
updatedAt: 0,
profileUpdatedAt: 200
})).toBe(true);
});
});

View File

@@ -45,7 +45,7 @@ interface PendingAvatarTransfer {
hash?: string;
}
type AvatarVersionState = Pick<User, 'avatarUrl' | 'avatarHash' | 'avatarUpdatedAt'> | undefined;
type AvatarVersionState = Pick<User, 'avatarUrl' | 'avatarHash' | 'avatarUpdatedAt' | 'profileUpdatedAt'> | undefined;
type RoomProfileState = Pick<User,
| 'id'
| 'oderId'
@@ -80,22 +80,31 @@ function shouldAcceptAvatarPayload(
return !!incomingHash && incomingHash !== existingUser.avatarHash;
}
function shouldAcceptProfilePayload(
existingUser: Pick<User, 'profileUpdatedAt'> | undefined,
incomingProfileUpdatedAt: number | undefined
): boolean {
return (incomingProfileUpdatedAt ?? 0) > (existingUser?.profileUpdatedAt ?? 0);
}
function hasSyncableUserData(user: Pick<User, 'avatarUpdatedAt' | 'profileUpdatedAt'> | null | undefined): boolean {
return (user?.avatarUpdatedAt ?? 0) > 0;
return (user?.avatarUpdatedAt ?? 0) > 0 || (user?.profileUpdatedAt ?? 0) > 0;
}
export function shouldRequestAvatarData(
existingUser: AvatarVersionState,
incomingAvatar: Pick<ChatEvent, 'avatarHash' | 'avatarUpdatedAt' | 'profileUpdatedAt'>
): boolean {
return shouldAcceptAvatarPayload(existingUser, incomingAvatar.avatarUpdatedAt ?? 0, incomingAvatar.avatarHash);
return shouldAcceptAvatarPayload(existingUser, incomingAvatar.avatarUpdatedAt ?? 0, incomingAvatar.avatarHash)
|| shouldAcceptProfilePayload(existingUser, incomingAvatar.profileUpdatedAt);
}
export function shouldApplyAvatarTransfer(
existingUser: AvatarVersionState,
transfer: Pick<PendingAvatarTransfer, 'hash' | 'updatedAt'>
transfer: Pick<PendingAvatarTransfer, 'hash' | 'updatedAt' | 'profileUpdatedAt'>
): boolean {
return shouldAcceptAvatarPayload(existingUser, transfer.updatedAt, transfer.hash);
return shouldAcceptAvatarPayload(existingUser, transfer.updatedAt, transfer.hash)
|| shouldAcceptProfilePayload(existingUser, transfer.profileUpdatedAt);
}
@Injectable()
@@ -258,17 +267,18 @@ export class UserAvatarEffects {
)
);
private buildAvatarSummary(user: Pick<User, 'oderId' | 'id' | 'avatarHash' | 'avatarUpdatedAt'>): ChatEvent {
private buildAvatarSummary(user: Pick<User, 'oderId' | 'id' | 'avatarHash' | 'avatarUpdatedAt' | 'profileUpdatedAt'>): ChatEvent {
return {
type: 'user-avatar-summary',
oderId: user.oderId || user.id,
avatarHash: user.avatarHash,
avatarUpdatedAt: user.avatarUpdatedAt || 0
avatarUpdatedAt: user.avatarUpdatedAt || 0,
profileUpdatedAt: user.profileUpdatedAt || 0
};
}
private handleAvatarSummary(event: ChatEvent, allUsers: User[], currentUser: User | null) {
if (!event.fromPeerId || !event.oderId || !event.avatarUpdatedAt) {
if (!event.fromPeerId || !event.oderId || (!event.avatarUpdatedAt && !event.profileUpdatedAt)) {
return EMPTY;
}
@@ -467,6 +477,8 @@ export class UserAvatarEffects {
oderId: userKey,
username: user.username,
displayName: user.displayName,
description: user.description,
profileUpdatedAt: user.profileUpdatedAt,
avatarHash: user.avatarHash,
avatarMime: blob ? (user.avatarMime || blob.type || 'image/webp') : undefined,
avatarUpdatedAt: user.avatarUpdatedAt || 0,

View File

@@ -178,6 +178,7 @@ function buildInactiveCameraState(user: User): User['cameraState'] {
}
function buildPresenceAwareUser(existingUser: User | undefined, incomingUser: User): User {
const presenceServerIds = mergePresenceServerIds(existingUser?.presenceServerIds, incomingUser.presenceServerIds);
const isOnline = (presenceServerIds?.length ?? 0) > 0 || incomingUser.isOnline === true;
const status = isOnline