Skip to content

Commit

Permalink
fix(keep-alive): ensure include/exclude regexp work with global flag (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
btea authored Aug 13, 2024
1 parent fee6697 commit 3653bc0
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
144 changes: 144 additions & 0 deletions packages/runtime-core/__tests__/components/KeepAlive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const timeout = (n: number = 0) => new Promise(r => setTimeout(r, n))
describe('KeepAlive', () => {
let one: ComponentOptions
let two: ComponentOptions
let oneTest: ComponentOptions
let views: Record<string, ComponentOptions>
let root: TestElement

Expand All @@ -49,6 +50,18 @@ describe('KeepAlive', () => {
deactivated: vi.fn(),
unmounted: vi.fn(),
}
oneTest = {
name: 'oneTest',
data: () => ({ msg: 'oneTest' }),
render(this: any) {
return h('div', this.msg)
},
created: vi.fn(),
mounted: vi.fn(),
activated: vi.fn(),
deactivated: vi.fn(),
unmounted: vi.fn(),
}
two = {
name: 'two',
data: () => ({ msg: 'two' }),
Expand All @@ -63,6 +76,7 @@ describe('KeepAlive', () => {
}
views = {
one,
oneTest,
two,
}
})
Expand Down Expand Up @@ -369,6 +383,128 @@ describe('KeepAlive', () => {
assertHookCalls(two, [2, 2, 0, 0, 2])
}

async function assertNameMatchWithFlag(props: KeepAliveProps) {
const outerRef = ref(true)
const viewRef = ref('one')
const App = {
render() {
return outerRef.value
? h(KeepAlive, props, () => h(views[viewRef.value]))
: null
},
}
render(h(App), root)

expect(serializeInner(root)).toBe(`<div>one</div>`)
assertHookCalls(one, [1, 1, 1, 0, 0])
assertHookCalls(oneTest, [0, 0, 0, 0, 0])
assertHookCalls(two, [0, 0, 0, 0, 0])

viewRef.value = 'oneTest'
await nextTick()
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
assertHookCalls(one, [1, 1, 1, 1, 0])
assertHookCalls(oneTest, [1, 1, 1, 0, 0])
assertHookCalls(two, [0, 0, 0, 0, 0])

viewRef.value = 'two'
await nextTick()
expect(serializeInner(root)).toBe(`<div>two</div>`)
assertHookCalls(one, [1, 1, 1, 1, 0])
assertHookCalls(oneTest, [1, 1, 1, 1, 0])
assertHookCalls(two, [1, 1, 0, 0, 0])

viewRef.value = 'one'
await nextTick()
expect(serializeInner(root)).toBe(`<div>one</div>`)
assertHookCalls(one, [1, 1, 2, 1, 0])
assertHookCalls(oneTest, [1, 1, 1, 1, 0])
assertHookCalls(two, [1, 1, 0, 0, 1])

viewRef.value = 'oneTest'
await nextTick()
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
assertHookCalls(one, [1, 1, 2, 2, 0])
assertHookCalls(oneTest, [1, 1, 2, 1, 0])
assertHookCalls(two, [1, 1, 0, 0, 1])

viewRef.value = 'two'
await nextTick()
expect(serializeInner(root)).toBe(`<div>two</div>`)
assertHookCalls(one, [1, 1, 2, 2, 0])
assertHookCalls(oneTest, [1, 1, 2, 2, 0])
assertHookCalls(two, [2, 2, 0, 0, 1])

// teardown
outerRef.value = false
await nextTick()
expect(serializeInner(root)).toBe(`<!---->`)
assertHookCalls(one, [1, 1, 2, 2, 1])
assertHookCalls(oneTest, [1, 1, 2, 2, 1])
assertHookCalls(two, [2, 2, 0, 0, 2])
}

async function assertNameMatchWithFlagExclude(props: KeepAliveProps) {
const outerRef = ref(true)
const viewRef = ref('one')
const App = {
render() {
return outerRef.value
? h(KeepAlive, props, () => h(views[viewRef.value]))
: null
},
}
render(h(App), root)

expect(serializeInner(root)).toBe(`<div>one</div>`)
assertHookCalls(one, [1, 1, 0, 0, 0])
assertHookCalls(oneTest, [0, 0, 0, 0, 0])
assertHookCalls(two, [0, 0, 0, 0, 0])

viewRef.value = 'oneTest'
await nextTick()
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
assertHookCalls(one, [1, 1, 0, 0, 1])
assertHookCalls(oneTest, [1, 1, 0, 0, 0])
assertHookCalls(two, [0, 0, 0, 0, 0])

viewRef.value = 'two'
await nextTick()
expect(serializeInner(root)).toBe(`<div>two</div>`)
assertHookCalls(one, [1, 1, 0, 0, 1])
assertHookCalls(oneTest, [1, 1, 0, 0, 1])
assertHookCalls(two, [1, 1, 1, 0, 0])

viewRef.value = 'one'
await nextTick()
expect(serializeInner(root)).toBe(`<div>one</div>`)
assertHookCalls(one, [2, 2, 0, 0, 1])
assertHookCalls(oneTest, [1, 1, 0, 0, 1])
assertHookCalls(two, [1, 1, 1, 1, 0])

viewRef.value = 'oneTest'
await nextTick()
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
assertHookCalls(one, [2, 2, 0, 0, 2])
assertHookCalls(oneTest, [2, 2, 0, 0, 1])
assertHookCalls(two, [1, 1, 1, 1, 0])

viewRef.value = 'two'
await nextTick()
expect(serializeInner(root)).toBe(`<div>two</div>`)
assertHookCalls(one, [2, 2, 0, 0, 2])
assertHookCalls(oneTest, [2, 2, 0, 0, 2])
assertHookCalls(two, [1, 1, 2, 1, 0])

// teardown
outerRef.value = false
await nextTick()
expect(serializeInner(root)).toBe(`<!---->`)
assertHookCalls(one, [2, 2, 0, 0, 2])
assertHookCalls(oneTest, [2, 2, 0, 0, 2])
assertHookCalls(two, [1, 1, 2, 2, 1])
}

describe('props', () => {
test('include (string)', async () => {
await assertNameMatch({ include: 'one' })
Expand All @@ -378,6 +514,10 @@ describe('KeepAlive', () => {
await assertNameMatch({ include: /^one$/ })
})

test('include (regex with g flag)', async () => {
await assertNameMatchWithFlag({ include: /one/g })
})

test('include (array)', async () => {
await assertNameMatch({ include: ['one'] })
})
Expand All @@ -390,6 +530,10 @@ describe('KeepAlive', () => {
await assertNameMatch({ exclude: /^two$/ })
})

test('exclude (regex with a flag)', async () => {
await assertNameMatchWithFlagExclude({ exclude: /one/g })
})

test('exclude (array)', async () => {
await assertNameMatch({ exclude: ['two'] })
})
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-core/src/components/KeepAlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ function matches(pattern: MatchPattern, name: string): boolean {
} else if (isString(pattern)) {
return pattern.split(',').includes(name)
} else if (isRegExp(pattern)) {
pattern.lastIndex = 0
return pattern.test(name)
}
/* istanbul ignore next */
Expand Down

0 comments on commit 3653bc0

Please sign in to comment.