Skip to content
Closed
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
Expand Up @@ -67,6 +67,7 @@ describe('structuredClone', () => {

expect(structuredClone(0)).toBe(0);
expect(structuredClone(1)).toBe(1);
expect(Object.is(structuredClone(-0), -0)).toBe(true);

expect(structuredClone(0n)).toBe(0n);
expect(structuredClone(1n)).toBe(1n);
Expand Down Expand Up @@ -99,6 +100,12 @@ describe('structuredClone', () => {
expect(booleanClone).not.toBe(booleanValue);
expect(booleanClone).toBeInstanceOf(Boolean);
expect(booleanClone.valueOf()).toBe(true);

const bigintValue = Object(1n);
const bigintClone = structuredClone(bigintValue);
expect(bigintClone).not.toBe(bigintValue);
expect(bigintClone).toBeInstanceOf(BigInt);
expect(bigintClone.valueOf()).toBe(1n);
});

it('throws with symbols, functions, WeakMap, WeakSet, Promise', () => {
Expand Down Expand Up @@ -223,6 +230,58 @@ describe('structuredClone', () => {
expect(clone).toEqual(value);
});

it('clones invalid dates', () => {
const value = new Date(NaN);
const clone = structuredClone(value);
expect(clone).not.toBe(value);
expect(clone).toBeInstanceOf(Date);
expect(Number.isNaN(clone.getTime())).toBe(true);
});

it('clones ArrayBuffer', () => {
const value = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).buffer;
const clone = structuredClone(value);
expect(clone).not.toBe(value);
expect(clone).toBeInstanceOf(ArrayBuffer);
expect([...new Uint8Array(clone)]).toEqual([0, 1, 2, 3, 4, 5, 6, 7]);
});

it('clones DataView', () => {
const buffer = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).buffer;
const value = new DataView(buffer);
const clone = structuredClone(value);
expect(clone).not.toBe(value);
expect(clone).toBeInstanceOf(DataView);
expect([...new Uint8Array(clone.buffer)]).toEqual([0, 1, 2, 3, 4, 5, 6, 7]);
});

it('clones typed arrays', () => {
const value = new Uint32Array([1, 2, 3]);
const clone = structuredClone(value);
expect(clone).not.toBe(value);
expect(clone).toBeInstanceOf(Uint32Array);
expect([...clone]).toEqual([1, 2, 3]);
});

it('preserves shared buffers between views', () => {
const buffer = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).buffer;
const value = {
typedArray: new Uint16Array(buffer, 2, 2),
dataView: new DataView(buffer, 1, 6),
buffer,
};

const clone = structuredClone(value);
expect(clone.buffer).not.toBe(buffer);
expect(clone.dataView.buffer).toBe(clone.buffer);
expect(clone.typedArray.buffer).toBe(clone.buffer);
expect(clone.dataView.byteOffset).toBe(value.dataView.byteOffset);
expect(clone.dataView.byteLength).toBe(value.dataView.byteLength);
expect(clone.typedArray.byteOffset).toBe(value.typedArray.byteOffset);
expect(clone.typedArray.length).toBe(value.typedArray.length);
expect([...clone.typedArray]).toEqual([...value.typedArray]);
});

it('clones errors', () => {
const cause = new Error('cause message');
const value = new Error('error message', {cause});
Expand Down Expand Up @@ -261,6 +320,53 @@ describe('structuredClone', () => {
expect(structuredClone(value).name).toBe('Error');
});

it('preserves error subclasses', () => {
expect(structuredClone(new Error('boom'))).toBeInstanceOf(Error);
expect(structuredClone(new EvalError('boom'))).toBeInstanceOf(EvalError);
expect(structuredClone(new RangeError('boom'))).toBeInstanceOf(RangeError);
expect(structuredClone(new ReferenceError('boom'))).toBeInstanceOf(
ReferenceError,
);
expect(structuredClone(new SyntaxError('boom'))).toBeInstanceOf(
SyntaxError,
);
expect(structuredClone(new TypeError('boom'))).toBeInstanceOf(TypeError);
expect(structuredClone(new URIError('boom'))).toBeInstanceOf(URIError);
});

it('clones aggregate errors', () => {
const innerError = new TypeError('inner');
const value = new AggregateError([innerError, {foo: 'bar'}], 'outer');
const clone = structuredClone(value);
const clonedErrors = Array.from(clone.errors);
const clonedInnerError = ensureInstance(clonedErrors[0], TypeError);

expect(clone).not.toBe(value);
expect(clone).toBeInstanceOf(AggregateError);
expect(clone.message).toBe(value.message);
expect(clone.stack).toBe(value.stack);
expect(clone.errors).not.toBe(value.errors);
expect(clonedInnerError).not.toBe(innerError);
expect(clonedInnerError.message).toBe(innerError.message);
expect(clonedErrors[1]).toEqual({foo: 'bar'});
});

it('clones __proto__ as an own property', () => {
const value = JSON.parse('{"__proto__":{"foo":"bar"}}');
const clone = structuredClone(value);
const clonedValue = nullthrows(
Object.getOwnPropertyDescriptor(clone, '__proto__'),
).value;
const originalValue = nullthrows(
Object.getOwnPropertyDescriptor(value, '__proto__'),
).value;

expect(clone.foo).toBeUndefined();
expect(Object.hasOwn(clone, '__proto__')).toBe(true);
expect(clonedValue).not.toBe(originalValue);
expect(clonedValue).toEqual({foo: 'bar'});
});

it('clones values deeply', () => {
const value = {
obj: {
Expand Down
Loading
Loading