Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { collab } from '@/proto/messages';
import { getAxios } from '@/application/services/js-services/http/core';

import { collabFullSyncBatch } from '../collab-api';

jest.mock('@/application/services/js-services/device-id', () => ({
getOrCreateDeviceId: jest.fn(() => 'test-device-id'),
}));

jest.mock('@/application/services/js-services/http/core', () => ({
executeAPIRequest: jest.fn(),
executeAPIVoidRequest: jest.fn(),
getAxios: jest.fn(),
parseRetryAfterSecs: jest.fn(),
}));

const mockGetAxios = getAxios as unknown as jest.Mock;

describe('collabFullSyncBatch', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('sends the encoded protobuf view instead of the pooled backing buffer', async () => {
const responseBody = collab.CollabBatchSyncResponse.encode(
collab.CollabBatchSyncResponse.create({
results: [],
responseCompression: collab.PayloadCompressionType.COMPRESSION_NONE,
})
).finish();
const post = jest.fn().mockResolvedValue({
status: 200,
data: responseBody,
headers: {},
});

mockGetAxios.mockReturnValue({ post });

await collabFullSyncBatch('workspace-id', [
{
objectId: 'object-id',
collabType: 0,
stateVector: new Uint8Array([1]),
docState: new Uint8Array([2]),
},
]);

const [, requestBody, config] = post.mock.calls[0];

expect(ArrayBuffer.isView(requestBody)).toBe(true);
expect(requestBody.byteLength).toBeLessThan(requestBody.buffer.byteLength);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (testing): This assertion makes the test brittle because it relies on the encoder always returning a view smaller than its backing buffer.

Depending on requestBody.byteLength < requestBody.buffer.byteLength makes this test fragile: a future protobuf encoder change could return a tightly sized Uint8Array, breaking the test while the behavior is still correct. The regression is specifically about Axios using .buffer (including zero padding), not about the current size relationship. To make this robust, either:

  • Create a larger ArrayBuffer in the test and a Uint8Array view over it, and use that as the request body so the condition is under your control, or
  • Remove this assertion and instead assert behavior that directly captures the regression (e.g., comparing what Axios’ default transform would send vs. what your override sends).

expect(config.transformRequest[0](requestBody)).toBe(requestBody);
});
});
3 changes: 3 additions & 0 deletions src/application/services/js-services/http/collab-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export async function collabFullSyncBatch(
'device-id': deviceId,
},
responseType: 'arraybuffer',
// Axios' default transform sends typed-array `.buffer`, which can include
// protobufjs' pooled zero padding beyond this Uint8Array view.
transformRequest: [(data: Uint8Array) => data],
validateStatus: (status) => status === 200 || status === 429 || status === 503,
});

Expand Down
Loading