- Create a src/index.ts with empty deepMerge function
- Create new test file importing it
- Make simple test to merge two object and let it fails
import { test, expect } from 'vitest'
import { deepMerge } from '../src'
test('shallow merge', () => {
const merged = deepMerge({
name: 'Matteo'
}, {
github: 'sot1986'
})
expect(merged).toEqual({
name: 'Matteo',
github: 'sot1986'
})
})
- Update the deepMerge function to pass the test
export function deepMerge(a, b) {
return Object.assign(a, b)
}
- Add one more test case for property overlap
test('shallow merge with property overlaps', () => {
const merged = deepMerge({
name: 'Matteo',
github: 'unknown'
}, {
github: 'sot1986',
twitter: 'none'
})
expect(merged).toEqual({
name: 'Matteo',
github: 'sot1986',
twitter: 'none'
})
})
- Move one until test fails. Consider arrays
test('shallow merge with array', () => {
const merged = deepMerge(
['vue', 'react'],
['svelte', 'solid']
)
expect(merged).toEqual(
['vue', 'react', 'svelte', 'solid']
)
})
- Update the function to handle array
export function deepMerge(a, b) {
if (Array.isArray(a)) {
return[ ...a, ...b]
}
return Object.assign(a, b)
}
- Make it working for deep merge
test('deep merge with overlaps', () => {
const merged = deepMerge({
name: 'Matteo',
accounts: {
github: 'unknown'
}
}, {
accounts: {
twitter: 'none'
}
})
expect(merged).toEqual({
name: 'Matteo',
accounts: {
github: 'unknown',
twitter: 'none'
}
})
})
Test fails. Because Object.assign not support more than 1 level merged
- update the function and ensure with skipping last test that everything works as well.
export function deepMerge(a, b) {
if (Array.isArray(a)) {
return[ ...a, ...b]
}
const merged = { ...a }
for (const key of Object.keys(b)) {
merged[key] = b[key]
}
return merged
}
test.skip('deep merge with overlaps', () => {
// ...
}
It works. Then remove the skip and see it is failing as expected.
- Update the deep merge to handle deep merge
export function deepMerge(a, b) {
if (Array.isArray(a)) {
return[ ...a, ...b]
}
const merged = { ...a }
for (const key of Object.keys(b)) {
if (typeof a[key] === 'object' || Array.isArray(a[key]))
merged[key] = deepMerge(a[key], b[key])
else
merged[key] = b[key]
}
return merged
}
- Ensure test throw errors when user insert values of different types First option
test.fails('throw errors on merging two different types', () => {
const merged = deepMerge(
['foo', 'bar'],
{ foo: 'bar' }
)
})
Hover this apprach does not distinguish how and when test fails.
Second option
test('throw errors on merging two different types', () => {
expect(() => deepMerge(
['foo', 'bar'],
{ foo: 'bar' }
)).toThrowError()
})
- Update function and test to check proper error is thrown
export function deepMerge(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
return[ ...a, ...b]
}
if (Array.isArray(a) || Array.isArray(b) || typeof a !== typeof b) {
throw new Error('Error: Can not merge two different types')
}
const merged = { ...a }
for (const key of Object.keys(b)) {
if (typeof a[key] === 'object' || Array.isArray(a[key]))
merged[key] = deepMerge(a[key], b[key])
else
merged[key] = b[key]
}
return merged
}
test('throw errors on merging two different types', () => {
expect(() => deepMerge(
['foo', 'bar'],
{ foo: 'bar' }
)).toThrowError('Error: Can not merge two different types')
})