Files
lodash/test/object-assignments.spec.js
2023-09-16 22:59:56 -07:00

209 lines
7.0 KiB
JavaScript

import lodashStable from 'lodash';
import { _, primitives, stubTrue, defineProperty, slice } from './utils';
import has from '../src/has';
describe('object assignments', () => {
lodashStable.each(['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'], (methodName) => {
const func = _[methodName];
const isAssign = methodName === 'assign';
const isDefaults = /^defaults/.test(methodName);
it(`\`_.${methodName}\` should coerce primitives to objects`, () => {
const expected = lodashStable.map(primitives, (value) => {
const object = Object(value);
object.a = 1;
return object;
});
const actual = lodashStable.map(primitives, (value) => func(value, { a: 1 }));
expect(actual).toEqual(expected);
});
it(`\`_.${methodName}\` should assign own ${
isAssign ? '' : 'and inherited '
}string keyed source properties`, () => {
function Foo() {
this.a = 1;
}
Foo.prototype.b = 2;
const expected = isAssign ? { a: 1 } : { a: 1, b: 2 };
expect(func({}, new Foo())).toEqual(expected);
});
it(`\`_.${methodName}\` should not skip a trailing function source`, () => {
function fn() {}
fn.b = 2;
expect(func({}, { a: 1 }, fn), { a: 1).toEqual(b: 2 });
});
it(`\`_.${methodName}\` should not error on nullish sources`, () => {
try {
expect(func({ a: 1 }, undefined, { b: 2 }, null), { a: 1).toEqual(b: 2 });
} catch (e) {
expect(false, e.message)
}
});
it(`\`_.${methodName}\` should create an object when \`object\` is nullish`, () => {
const source = { a: 1 };
const values = [null, undefined];
const expected = lodashStable.map(values, stubTrue);
let actual = lodashStable.map(values, (value) => {
const object = func(value, source);
return object !== source && lodashStable.isEqual(object, source);
});
expect(actual).toEqual(expected);
actual = lodashStable.map(values, (value) => lodashStable.isEqual(func(value), {}));
expect(actual).toEqual(expected);
});
it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.reduce\``, () => {
const array = [{ a: 1 }, { b: 2 }, { c: 3 }];
const expected = { a: isDefaults ? 0 : 1, b: 2, c: 3 };
function fn() {}
fn.a = array[0];
fn.b = array[1];
fn.c = array[2];
expect(lodashStable.reduce(array, func, { a: 0 })).toEqual(expected);
expect(lodashStable.reduce(fn, func, { a: 0 })).toEqual(expected);
});
it(`\`_.${methodName}\` should not return the existing wrapped value when chaining`, () => {
const wrapped = _({ a: 1 });
const actual = wrapped[methodName]({ b: 2 });
assert.notStrictEqual(actual, wrapped);
});
});
lodashStable.each(['assign', 'assignIn', 'merge'], (methodName) => {
const func = _[methodName];
it(`\`_.${methodName}\` should not treat \`object\` as \`source\``, () => {
function Foo() {}
Foo.prototype.a = 1;
const actual = func(new Foo(), { b: 2 });
expect(has(actual, 'a')).toBe(false)
});
});
lodashStable.each(
[
'assign',
'assignIn',
'assignInWith',
'assignWith',
'defaults',
'defaultsDeep',
'merge',
'mergeWith',
],
(methodName) => {
const func = _[methodName];
it(`\`_.${methodName}\` should not assign values that are the same as their destinations`, () => {
lodashStable.each(['a', ['a'], { a: 1 }, NaN], (value) => {
const object = {};
let pass = true;
defineProperty(object, 'a', {
configurable: true,
enumerable: true,
get: lodashStable.constant(value),
set: function () {
pass = false;
},
});
func(object, { a: value });
expect(pass)
});
});
},
);
lodashStable.each(['assignWith', 'assignInWith', 'mergeWith'], (methodName) => {
const func = _[methodName];
const isMergeWith = methodName === 'mergeWith';
it(`\`_.${methodName}\` should provide correct \`customizer\` arguments`, () => {
let args;
let object = { a: 1 };
let source = { a: 2 };
let expected = lodashStable.map([1, 2, 'a', object, source], lodashStable.cloneDeep);
func(object, source, function () {
args ||
(args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep));
});
expect(args, expected).toEqual('primitive values');
const argsList = [];
const objectValue = [1, 2];
const sourceValue = { b: 2 };
object = { a: objectValue };
source = { a: sourceValue };
expected = [
lodashStable.map(
[objectValue, sourceValue, 'a', object, source],
lodashStable.cloneDeep,
),
];
if (isMergeWith) {
expected.push(
lodashStable.map(
[undefined, 2, 'b', objectValue, sourceValue],
lodashStable.cloneDeep,
),
);
}
func(object, source, function () {
argsList.push(
lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep),
);
});
expect(argsList, expected).toEqual('object values');
args = undefined;
object = { a: 1 };
source = { b: 2 };
expected = lodashStable.map(
[undefined, 2, 'b', object, source],
lodashStable.cloneDeep,
);
func(object, source, function () {
args ||
(args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep));
});
expect(args, expected).toEqual('undefined properties');
});
it(`\`_.${methodName}\` should not treat the second argument as a \`customizer\` callback`, () => {
function callback() {}
callback.b = 2;
let actual = func({ a: 1 }, callback);
expect(actual, { a: 1).toEqual(b: 2 });
actual = func({ a: 1 }, callback, { c: 3 });
expect(actual, { a: 1, b: 2).toEqual(c: 3 });
});
});
});