Skip to content

Commit

Permalink
fix(core): configure should use the parent of the current instance, t…
Browse files Browse the repository at this point in the history
…o avoid duplication (#5147)
  • Loading branch information
nperez0111 committed May 14, 2024
1 parent 6049985 commit 4db463c
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/core/src/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ export class Extension<Options = any, Storage = any> {
// with different calls of `configure`
const extension = this.extend()

extension.parent = this.parent
extension.options = mergeDeep(this.options as Record<string, any>, options) as Options

extension.storage = callOrReturn(
Expand Down
221 changes: 221 additions & 0 deletions tests/cypress/integration/core/extendExtensions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@ describe('extend extensions', () => {
})
})

it('should have a parent', () => {
const extension = Extension
.create({
addAttributes() {
return {
foo: {},
}
},
})

const newExtension = extension
.extend({
addAttributes() {
return {
bar: {},
}
},
})

const parent = newExtension.parent

expect(parent).to.eq(extension)
})

it('should merge configs', () => {
const extension = Extension
.create({
Expand Down Expand Up @@ -104,6 +128,40 @@ describe('extend extensions', () => {
})
})

it('should set parents multiple times', () => {
const grandparentExtension = Extension
.create({
addAttributes() {
return {
foo: {},
}
},
})

const parentExtension = grandparentExtension
.extend({
addAttributes() {
return {
...this.parent?.(),
bar: {},
}
},
})

const childExtension = parentExtension
.extend({
addAttributes() {
return {
...this.parent?.(),
baz: {},
}
},
})

expect(parentExtension.parent).to.eq(grandparentExtension)
expect(childExtension.parent).to.eq(parentExtension)
})

it('should merge configs without direct parent configuration', () => {
const extension = Extension
.create({
Expand All @@ -130,4 +188,167 @@ describe('extend extensions', () => {
bar: {},
})
})

it('should call ancestors only once', () => {
const callCounts = {
grandparent: 0,
parent: 0,
child: 0,
}

const extension = Extension
.create({
addAttributes() {
callCounts.grandparent += 1
return {
foo: {},
}
},
})
.extend({
addAttributes() {
callCounts.parent += 1
return {
...this.parent?.(),
bar: {},
}
},
})
.extend({
addAttributes() {
callCounts.child += 1
return {
...this.parent?.(),
bar: {},
}
},
})

getExtensionField(extension, 'addAttributes')()

expect(callCounts).to.deep.eq({
grandparent: 1,
parent: 1,
child: 1,
})
})

it('should call ancestors only once on configure', () => {
const callCounts = {
grandparent: 0,
parent: 0,
child: 0,
}

const extension = Extension
.create({
addAttributes() {
callCounts.grandparent += 1
return {
foo: {},
}
},
})
.extend({
addAttributes() {
callCounts.parent += 1
return {
...this.parent?.(),
bar: {},
}
},
})
.extend({
addAttributes() {
callCounts.child += 1
return {
...this.parent?.(),
bar: {},
}
},
})
.configure({
baz: {},
})

getExtensionField(extension, 'addAttributes')()

expect(callCounts).to.deep.eq({
grandparent: 1,
parent: 1,
child: 1,
})
})

it('should use grandparent as parent on configure (not parent)', () => {
const grandparentExtension = Extension
.create({
addAttributes() {
return {
foo: {},
}
},
})

const parentExtension = grandparentExtension
.extend({
addAttributes() {
return {
...this.parent?.(),
bar: {},
}
},
})

const childExtension = parentExtension
.configure({
baz: {},
})

expect(parentExtension.parent).to.eq(grandparentExtension)
expect(childExtension.parent).to.eq(grandparentExtension)
})

it('should use parent\'s config on `configure`', () => {
const grandparentExtension = Extension
.create({
name: 'grandparent',
addAttributes() {
return {
foo: {},
}
},
})

const parentExtension = grandparentExtension
.extend({
name: 'parent',
addAttributes() {
return {
...this.parent?.(),
bar: {},
}
},
})

const childExtension = parentExtension
.configure({
baz: {},
})

expect(childExtension.config.name).to.eq('parent')
})

it('should inherit config on configure', () => {

const parentExtension = Extension
.create({
name: 'did-inherit',
})

const childExtension = parentExtension
.configure()

expect(childExtension.config.name).to.eq('did-inherit')
})
})
51 changes: 51 additions & 0 deletions tests/cypress/integration/core/extensionOptions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,40 @@ describe('extension options', () => {
})
})

it('should be extendable multiple times', () => {
const extension = Extension.create({
addOptions() {
return {
foo: 1,
bar: 1,
}
},
}).extend({
addOptions() {
return {
...this.parent?.(),
baz: 1,
}
},
})

const newExtension = extension.extend({
addOptions() {
return {
...this.parent?.(),
bax: 1,
}
},
})

expect(newExtension.options).to.deep.eq({
foo: 1,
bar: 1,
baz: 1,
bax: 1,
})
})

it('should be overwritable', () => {
const extension = Extension
.create({
Expand Down Expand Up @@ -138,6 +172,23 @@ describe('extension options', () => {
})
})

it('should configure retaining existing config', () => {
const extension = Extension.create({
name: 'parent',
addOptions() {
return {
foo: 1,
bar: 1,
}
},
})

const newExtension = extension
.configure()

expect(newExtension.config.name).to.eq('parent')
})

it('should create its own instance on configure', () => {
const extension = Extension
.create({
Expand Down

0 comments on commit 4db463c

Please sign in to comment.