Harden optimistic comment IDs
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
52bb4ea37a
commit
cfb7dd4818
2 changed files with 34 additions and 2 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
applyOptimisticIssueCommentUpdate,
|
applyOptimisticIssueCommentUpdate,
|
||||||
createOptimisticIssueComment,
|
createOptimisticIssueComment,
|
||||||
|
|
@ -7,6 +7,11 @@ import {
|
||||||
} from "./optimistic-issue-comments";
|
} from "./optimistic-issue-comments";
|
||||||
|
|
||||||
describe("optimistic issue comments", () => {
|
describe("optimistic issue comments", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
it("creates a pending optimistic comment for the current user", () => {
|
it("creates a pending optimistic comment for the current user", () => {
|
||||||
const comment = createOptimisticIssueComment({
|
const comment = createOptimisticIssueComment({
|
||||||
companyId: "company-1",
|
companyId: "company-1",
|
||||||
|
|
@ -22,6 +27,25 @@ describe("optimistic issue comments", () => {
|
||||||
expect(comment.authorAgentId).toBeNull();
|
expect(comment.authorAgentId).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("falls back when crypto.randomUUID is unavailable", () => {
|
||||||
|
vi.stubGlobal("crypto", {});
|
||||||
|
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_746_000_000_000);
|
||||||
|
const mathSpy = vi.spyOn(Math, "random").mockReturnValue(0.123456789);
|
||||||
|
|
||||||
|
const comment = createOptimisticIssueComment({
|
||||||
|
companyId: "company-1",
|
||||||
|
issueId: "issue-1",
|
||||||
|
body: "Working on it",
|
||||||
|
authorUserId: "board-1",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(comment.id).toBe("optimistic-1746000000000-4fzzzxjy");
|
||||||
|
expect(comment.clientId).toBe(comment.id);
|
||||||
|
|
||||||
|
nowSpy.mockRestore();
|
||||||
|
mathSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it("merges optimistic comments into the server thread in chronological order", () => {
|
it("merges optimistic comments into the server thread in chronological order", () => {
|
||||||
const merged = mergeIssueComments(
|
const merged = mergeIssueComments(
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,14 @@ function toTimestamp(value: Date | string) {
|
||||||
return new Date(value).getTime();
|
return new Date(value).getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createOptimisticCommentId() {
|
||||||
|
const randomUuid = globalThis.crypto?.randomUUID?.();
|
||||||
|
if (randomUuid) {
|
||||||
|
return `optimistic-${randomUuid}`;
|
||||||
|
}
|
||||||
|
return `optimistic-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
||||||
|
}
|
||||||
|
|
||||||
export function sortIssueComments<T extends { createdAt: Date | string; id: string }>(comments: T[]) {
|
export function sortIssueComments<T extends { createdAt: Date | string; id: string }>(comments: T[]) {
|
||||||
return [...comments].sort((a, b) => {
|
return [...comments].sort((a, b) => {
|
||||||
const createdAtDiff = toTimestamp(a.createdAt) - toTimestamp(b.createdAt);
|
const createdAtDiff = toTimestamp(a.createdAt) - toTimestamp(b.createdAt);
|
||||||
|
|
@ -31,7 +39,7 @@ export function createOptimisticIssueComment(params: {
|
||||||
authorUserId: string | null;
|
authorUserId: string | null;
|
||||||
}): OptimisticIssueComment {
|
}): OptimisticIssueComment {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const clientId = `optimistic-${crypto.randomUUID()}`;
|
const clientId = createOptimisticCommentId();
|
||||||
return {
|
return {
|
||||||
id: clientId,
|
id: clientId,
|
||||||
clientId,
|
clientId,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue