1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-21 18:53:29 +00:00

Conflict resolution

This commit is contained in:
Carlos Gonçalves
2024-04-02 17:18:45 +01:00
parent 8a1df6671a
commit 0c0c2039ed
699 changed files with 17230 additions and 8095 deletions

View File

@@ -70,6 +70,9 @@ export class FakeAccountService implements AccountService {
}
async switchAccount(userId: UserId): Promise<void> {
const next =
userId == null ? null : { id: userId, ...this.accountsSubject["_buffer"]?.[0]?.[userId] };
this.activeAccountSubject.next(next);
await this.mock.switchAccount(userId);
}
}

View File

@@ -0,0 +1,54 @@
describe("toAlmostEqual custom matcher", () => {
it("matches identical Dates", () => {
const date = new Date();
expect(date).toAlmostEqual(date);
});
it("matches when older but within default ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() - 5);
expect(date).toAlmostEqual(olderDate);
});
it("matches when newer but within default ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() + 5);
expect(date).toAlmostEqual(olderDate);
});
it("doesn't match if older than default ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() - 11);
expect(date).not.toAlmostEqual(olderDate);
});
it("doesn't match if newer than default ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() + 11);
expect(date).not.toAlmostEqual(olderDate);
});
it("matches when older but within custom ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() - 15);
expect(date).toAlmostEqual(olderDate, 20);
});
it("matches when newer but within custom ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() + 15);
expect(date).toAlmostEqual(olderDate, 20);
});
it("doesn't match if older than custom ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() - 21);
expect(date).not.toAlmostEqual(olderDate, 20);
});
it("doesn't match if newer than custom ms", () => {
const date = new Date();
const olderDate = new Date(date.getTime() + 21);
expect(date).not.toAlmostEqual(olderDate, 20);
});
});

View File

@@ -0,0 +1,20 @@
/**
* Matches the expected date within an optional ms precision
* @param received The received date
* @param expected The expected date
* @param msPrecision The optional precision in milliseconds
*/
export const toAlmostEqual: jest.CustomMatcher = function (
received: Date,
expected: Date,
msPrecision: number = 10,
) {
const receivedTime = received.getTime();
const expectedTime = expected.getTime();
const difference = Math.abs(receivedTime - expectedTime);
return {
pass: difference <= msPrecision,
message: () =>
`expected ${received} to be within ${msPrecision}ms of ${expected} (actual difference: ${difference}ms)`,
};
};

View File

@@ -0,0 +1,86 @@
import { Observable, Subscription, firstValueFrom, throwError, timeout } from "rxjs";
/** Test class to enable async awaiting of observable emissions */
export class ObservableTracker<T> {
private subscription: Subscription;
emissions: T[] = [];
constructor(private observable: Observable<T>) {
this.emissions = this.trackEmissions(observable);
}
/** Unsubscribes from the observable */
unsubscribe() {
this.subscription.unsubscribe();
}
/**
* Awaits the next emission from the observable, or throws if the timeout is exceeded
* @param msTimeout The maximum time to wait for another emission before throwing
*/
async expectEmission(msTimeout = 50) {
await firstValueFrom(
this.observable.pipe(
timeout({
first: msTimeout,
with: () => throwError(() => new Error("Timeout exceeded waiting for another emission.")),
}),
),
);
}
/** Awaits until the the total number of emissions observed by this tracker equals or exceeds {@link count}
* @param count The number of emissions to wait for
*/
async pauseUntilReceived(count: number, msTimeout = 50): Promise<T[]> {
for (let i = 0; i < count - this.emissions.length; i++) {
await this.expectEmission(msTimeout);
}
return this.emissions;
}
private trackEmissions<T>(observable: Observable<T>): T[] {
const emissions: T[] = [];
this.subscription = observable.subscribe((value) => {
switch (value) {
case undefined:
case null:
emissions.push(value);
return;
default:
// process by type
break;
}
switch (typeof value) {
case "string":
case "number":
case "boolean":
emissions.push(value);
break;
case "symbol":
// Cheating types to make symbols work at all
emissions.push(value.toString() as T);
break;
default: {
emissions.push(clone(value));
}
}
});
return emissions;
}
}
function clone(value: any): any {
if (global.structuredClone != undefined) {
return structuredClone(value);
} else {
return JSON.parse(JSON.stringify(value));
}
}
/** A test helper that builds an @see{@link ObservableTracker}, which can be used to assert things about the
* emissions of the given observable
* @param observable The observable to track
*/
export function subscribeTo<T>(observable: Observable<T>) {
return new ObservableTracker(observable);
}