Skip to content

Commit

Permalink
Adds test, fix bug on delete component
Browse files Browse the repository at this point in the history
  • Loading branch information
foyarash committed Feb 12, 2020
1 parent 3e2e4e6 commit edaee35
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 49 deletions.
9 changes: 0 additions & 9 deletions src/core/models/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ export type AppState = {
overlay: undefined | Overlay
}

export const generateId = () => {
return `comp-${(
Date.now().toString(36) +
Math.random()
.toString(36)
.substr(2, 5)
).toUpperCase()}`
}

const app = createModel({
state: {
showLayout: true,
Expand Down
46 changes: 7 additions & 39 deletions src/core/models/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { createModel } from '@rematch/core'
import { DEFAULT_PROPS } from '../../utils/defaultProps'
import omit from 'lodash/omit'
import templates, { TemplateType } from '../../templates'
import { generateId } from './app'
import { generateId } from '../../utils/generateId'
import { duplicateComponent, deleteComponent } from '../../utils/recursive'

export type ComponentsState = {
components: IComponents
Expand Down Expand Up @@ -98,21 +99,7 @@ const components = createModel({
}
}

const deleteRecursive = (
children: IComponent['children'],
id: IComponent['id'],
) => {
children.forEach(child => {
updatedComponents[child] &&
deleteRecursive(updatedComponents[child].children, componentId)
})

updatedComponents = omit(updatedComponents, id)
}

deleteRecursive(component.children, componentId)

updatedComponents = omit(updatedComponents, componentId)
updatedComponents = deleteComponent(component, updatedComponents)

return {
...state,
Expand Down Expand Up @@ -264,29 +251,10 @@ const components = createModel({
if (selectedComponent.id !== DEFAULT_ID) {
const parentElement = state.components[selectedComponent.parent]

const clonedComponents: IComponents = {}

const cloneComponent = (component: IComponent) => {
const newid = generateId()
const children = component.children.map(child => {
return cloneComponent(state.components[child])
})

clonedComponents[newid] = {
...component,
id: newid,
props: { ...component.props },
children,
}

children.forEach(child => {
clonedComponents[child].parent = newid
})

return newid
}

const newId = cloneComponent(selectedComponent)
const { newId, clonedComponents } = duplicateComponent(
selectedComponent,
state.components,
)

return {
...state,
Expand Down
2 changes: 1 addition & 1 deletion src/core/models/composer/composer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DEFAULT_PROPS } from '../../../utils/defaultProps'
import { generateId } from '../app'
import { generateId } from '../../../utils/generateId'

type AddNode = {
type: ComponentType
Expand Down
8 changes: 8 additions & 0 deletions src/utils/generateId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const generateId = () => {
return `comp-${(
Date.now().toString(36) +
Math.random()
.toString(36)
.substr(2, 5)
).toUpperCase()}`
}
127 changes: 127 additions & 0 deletions src/utils/recursive.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { generateId } from './generateId'
import { duplicateComponent, deleteComponent } from './recursive'

jest.mock('./generateId')

const mockGenerateId: jest.Mock<typeof generateId> = generateId as any

describe('recursive functions', () => {
let id = 1
let mockFn: typeof mockGenerateId

beforeAll(() => {
// @ts-ignore
mockFn = mockGenerateId.mockImplementation(() => {
return `comp-${id++}`
})
})

afterEach(() => {
id = 1
})

afterAll(() => {
mockFn.mockClear()
})

it('should duplicate a Box component containing an Avatar', () => {
const initialComponents: IComponents = {}

const first = generateId()
const second = generateId()

initialComponents.root = {
id: 'root',
type: 'Box',
parent: 'root',
props: {},
children: [first],
}

initialComponents[first] = {
id: first,
type: 'Box',
parent: 'root',
props: {},
children: [second],
}

initialComponents[second] = {
id: second,
type: 'Avatar',
parent: first,
props: {},
children: [],
}

const { clonedComponents } = duplicateComponent(
initialComponents[first],
initialComponents,
)

expect(Object.keys(clonedComponents).length).toEqual(2)

const finalTree = {
...initialComponents,
...clonedComponents,
}

const avatars = Object.keys(finalTree).filter(
compKey => finalTree[compKey].type === 'Avatar',
)
const boxes = Object.keys(finalTree).filter(
compKey => finalTree[compKey].type === 'Box',
)

expect(avatars.length).toEqual(2)
expect(boxes.length).toEqual(3)
})

it('should remove a Box containing an avatar and a badge', () => {
const initialComponents: IComponents = {}

const first = generateId()
const second = generateId()
const third = generateId()

initialComponents.root = {
id: 'root',
type: 'Box',
parent: 'root',
props: {},
children: [first],
}

initialComponents[first] = {
id: first,
type: 'Box',
parent: 'root',
props: {},
children: [second],
}

initialComponents[second] = {
id: second,
type: 'Avatar',
parent: first,
props: {},
children: [third],
}

initialComponents[third] = {
id: third,
type: 'AvatarBadge',
parent: second,
props: {},
children: [],
}

const updatedComponents = deleteComponent(
initialComponents[first],
initialComponents,
)

expect(Object.keys(updatedComponents).length).toEqual(1)
expect(Object.keys(updatedComponents)[0]).toEqual('root')
})
})
58 changes: 58 additions & 0 deletions src/utils/recursive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import omit from 'lodash/omit'
import { generateId } from './generateId'

export const duplicateComponent = (
componentToClone: IComponent,
components: IComponents,
) => {
const clonedComponents: IComponents = {}

const cloneComponent = (component: IComponent) => {
const newid = generateId()
const children = component.children.map(child => {
return cloneComponent(components[child])
})

clonedComponents[newid] = {
...component,
id: newid,
props: { ...component.props },
children,
}

children.forEach(child => {
clonedComponents[child].parent = newid
})

return newid
}

const newId = cloneComponent(componentToClone)

return {
newId,
clonedComponents,
}
}

export const deleteComponent = (
component: IComponent,
components: IComponents,
) => {
let updatedComponents = { ...components }
const deleteRecursive = (
children: IComponent['children'],
id: IComponent['id'],
) => {
children.forEach(child => {
updatedComponents[child] &&
deleteRecursive(updatedComponents[child].children, child)
})

updatedComponents = omit(updatedComponents, id)
}

deleteRecursive(component.children, component.id)
updatedComponents = omit(updatedComponents, component.id)
return updatedComponents
}

0 comments on commit edaee35

Please sign in to comment.