Skip to content

Instantly share code, notes, and snippets.

@mmacphail
Created February 19, 2025 14:46
Show Gist options
  • Select an option

  • Save mmacphail/fadf7dc008746f03672b9d108782e666 to your computer and use it in GitHub Desktop.

Select an option

Save mmacphail/fadf7dc008746f03672b9d108782e666 to your computer and use it in GitHub Desktop.
Y.JS learning spike
import { describe, it, expect, beforeEach } from 'vitest';
import * as Y from 'yjs';
import { encodeStateAsUpdate, applyUpdate } from 'yjs';
describe('Y.js Learning Spike', () => {
let doc;
let text;
let doc2;
let text2;
let update;
beforeEach(() => {
doc = new Y.Doc();
text = doc.getText('text');
doc2 = new Y.Doc();
text2 = doc2.getText('text');
text.insert(0, 'Hello');
text2.insert(0, 'World');
update = encodeStateAsUpdate(doc);
});
it('should apply updates', () => {
const doc = new Y.Doc();
const text = doc.getText('text');
text.insert(0, 'Hello');
expect(text.toString()).toBe('Hello');
const update = encodeStateAsUpdate(doc);
const doc2 = new Y.Doc();
const text2 = doc2.getText('text');
text2.insert(0, 'World');
expect(text2.toString()).toBe('World');
applyUpdate(doc2, update);
expect(text2.toString()).toContain('Hello');
expect(text2.toString()).toContain('World');
});
it('should trigger observers when updating', () => {
let changed = false;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
text2.observe((event) => {
changed = true;
});
applyUpdate(doc2, update);
expect(changed).toBe(true);
});
it('should allow rolling back changes using UndoManager', () => {
const undoManager = new Y.UndoManager(text);
expect(text.toString()).toBe('Hello');
text.insert(5, ' World');
expect(text.toString()).toBe('Hello World');
undoManager.undo();
expect(text.toString()).toBe('Hello');
undoManager.redo();
expect(text.toString()).toBe('Hello World');
});
it('should handle transactions as atomic operations', () => {
let observerCallCount = 0;
// Set up observer to count changes
text.observe(() => {
observerCallCount++;
});
// Multiple operations without transaction - will trigger observer multiple times
text.insert(0, 'Hello');
text.insert(5, ' ');
text.insert(6, 'World');
expect(observerCallCount).toBe(3);
// Reset counter
observerCallCount = 0;
// Multiple operations within a transaction - will trigger observer only once
doc.transact(() => {
text.delete(0, text.length); // Clear text
text.insert(0, 'Hello');
text.insert(5, ' ');
text.insert(6, 'World');
});
expect(observerCallCount).toBe(1);
expect(text.toString()).toBe('Hello World');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment