Skip to content

Commit 3653bc0

Browse files
authored
fix(keep-alive): ensure include/exclude regexp work with global flag (#11595)
1 parent fee6697 commit 3653bc0

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

Diff for: packages/runtime-core/__tests__/components/KeepAlive.spec.ts

+144
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const timeout = (n: number = 0) => new Promise(r => setTimeout(r, n))
3232
describe('KeepAlive', () => {
3333
let one: ComponentOptions
3434
let two: ComponentOptions
35+
let oneTest: ComponentOptions
3536
let views: Record<string, ComponentOptions>
3637
let root: TestElement
3738

@@ -49,6 +50,18 @@ describe('KeepAlive', () => {
4950
deactivated: vi.fn(),
5051
unmounted: vi.fn(),
5152
}
53+
oneTest = {
54+
name: 'oneTest',
55+
data: () => ({ msg: 'oneTest' }),
56+
render(this: any) {
57+
return h('div', this.msg)
58+
},
59+
created: vi.fn(),
60+
mounted: vi.fn(),
61+
activated: vi.fn(),
62+
deactivated: vi.fn(),
63+
unmounted: vi.fn(),
64+
}
5265
two = {
5366
name: 'two',
5467
data: () => ({ msg: 'two' }),
@@ -63,6 +76,7 @@ describe('KeepAlive', () => {
6376
}
6477
views = {
6578
one,
79+
oneTest,
6680
two,
6781
}
6882
})
@@ -369,6 +383,128 @@ describe('KeepAlive', () => {
369383
assertHookCalls(two, [2, 2, 0, 0, 2])
370384
}
371385

386+
async function assertNameMatchWithFlag(props: KeepAliveProps) {
387+
const outerRef = ref(true)
388+
const viewRef = ref('one')
389+
const App = {
390+
render() {
391+
return outerRef.value
392+
? h(KeepAlive, props, () => h(views[viewRef.value]))
393+
: null
394+
},
395+
}
396+
render(h(App), root)
397+
398+
expect(serializeInner(root)).toBe(`<div>one</div>`)
399+
assertHookCalls(one, [1, 1, 1, 0, 0])
400+
assertHookCalls(oneTest, [0, 0, 0, 0, 0])
401+
assertHookCalls(two, [0, 0, 0, 0, 0])
402+
403+
viewRef.value = 'oneTest'
404+
await nextTick()
405+
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
406+
assertHookCalls(one, [1, 1, 1, 1, 0])
407+
assertHookCalls(oneTest, [1, 1, 1, 0, 0])
408+
assertHookCalls(two, [0, 0, 0, 0, 0])
409+
410+
viewRef.value = 'two'
411+
await nextTick()
412+
expect(serializeInner(root)).toBe(`<div>two</div>`)
413+
assertHookCalls(one, [1, 1, 1, 1, 0])
414+
assertHookCalls(oneTest, [1, 1, 1, 1, 0])
415+
assertHookCalls(two, [1, 1, 0, 0, 0])
416+
417+
viewRef.value = 'one'
418+
await nextTick()
419+
expect(serializeInner(root)).toBe(`<div>one</div>`)
420+
assertHookCalls(one, [1, 1, 2, 1, 0])
421+
assertHookCalls(oneTest, [1, 1, 1, 1, 0])
422+
assertHookCalls(two, [1, 1, 0, 0, 1])
423+
424+
viewRef.value = 'oneTest'
425+
await nextTick()
426+
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
427+
assertHookCalls(one, [1, 1, 2, 2, 0])
428+
assertHookCalls(oneTest, [1, 1, 2, 1, 0])
429+
assertHookCalls(two, [1, 1, 0, 0, 1])
430+
431+
viewRef.value = 'two'
432+
await nextTick()
433+
expect(serializeInner(root)).toBe(`<div>two</div>`)
434+
assertHookCalls(one, [1, 1, 2, 2, 0])
435+
assertHookCalls(oneTest, [1, 1, 2, 2, 0])
436+
assertHookCalls(two, [2, 2, 0, 0, 1])
437+
438+
// teardown
439+
outerRef.value = false
440+
await nextTick()
441+
expect(serializeInner(root)).toBe(`<!---->`)
442+
assertHookCalls(one, [1, 1, 2, 2, 1])
443+
assertHookCalls(oneTest, [1, 1, 2, 2, 1])
444+
assertHookCalls(two, [2, 2, 0, 0, 2])
445+
}
446+
447+
async function assertNameMatchWithFlagExclude(props: KeepAliveProps) {
448+
const outerRef = ref(true)
449+
const viewRef = ref('one')
450+
const App = {
451+
render() {
452+
return outerRef.value
453+
? h(KeepAlive, props, () => h(views[viewRef.value]))
454+
: null
455+
},
456+
}
457+
render(h(App), root)
458+
459+
expect(serializeInner(root)).toBe(`<div>one</div>`)
460+
assertHookCalls(one, [1, 1, 0, 0, 0])
461+
assertHookCalls(oneTest, [0, 0, 0, 0, 0])
462+
assertHookCalls(two, [0, 0, 0, 0, 0])
463+
464+
viewRef.value = 'oneTest'
465+
await nextTick()
466+
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
467+
assertHookCalls(one, [1, 1, 0, 0, 1])
468+
assertHookCalls(oneTest, [1, 1, 0, 0, 0])
469+
assertHookCalls(two, [0, 0, 0, 0, 0])
470+
471+
viewRef.value = 'two'
472+
await nextTick()
473+
expect(serializeInner(root)).toBe(`<div>two</div>`)
474+
assertHookCalls(one, [1, 1, 0, 0, 1])
475+
assertHookCalls(oneTest, [1, 1, 0, 0, 1])
476+
assertHookCalls(two, [1, 1, 1, 0, 0])
477+
478+
viewRef.value = 'one'
479+
await nextTick()
480+
expect(serializeInner(root)).toBe(`<div>one</div>`)
481+
assertHookCalls(one, [2, 2, 0, 0, 1])
482+
assertHookCalls(oneTest, [1, 1, 0, 0, 1])
483+
assertHookCalls(two, [1, 1, 1, 1, 0])
484+
485+
viewRef.value = 'oneTest'
486+
await nextTick()
487+
expect(serializeInner(root)).toBe(`<div>oneTest</div>`)
488+
assertHookCalls(one, [2, 2, 0, 0, 2])
489+
assertHookCalls(oneTest, [2, 2, 0, 0, 1])
490+
assertHookCalls(two, [1, 1, 1, 1, 0])
491+
492+
viewRef.value = 'two'
493+
await nextTick()
494+
expect(serializeInner(root)).toBe(`<div>two</div>`)
495+
assertHookCalls(one, [2, 2, 0, 0, 2])
496+
assertHookCalls(oneTest, [2, 2, 0, 0, 2])
497+
assertHookCalls(two, [1, 1, 2, 1, 0])
498+
499+
// teardown
500+
outerRef.value = false
501+
await nextTick()
502+
expect(serializeInner(root)).toBe(`<!---->`)
503+
assertHookCalls(one, [2, 2, 0, 0, 2])
504+
assertHookCalls(oneTest, [2, 2, 0, 0, 2])
505+
assertHookCalls(two, [1, 1, 2, 2, 1])
506+
}
507+
372508
describe('props', () => {
373509
test('include (string)', async () => {
374510
await assertNameMatch({ include: 'one' })
@@ -378,6 +514,10 @@ describe('KeepAlive', () => {
378514
await assertNameMatch({ include: /^one$/ })
379515
})
380516

517+
test('include (regex with g flag)', async () => {
518+
await assertNameMatchWithFlag({ include: /one/g })
519+
})
520+
381521
test('include (array)', async () => {
382522
await assertNameMatch({ include: ['one'] })
383523
})
@@ -390,6 +530,10 @@ describe('KeepAlive', () => {
390530
await assertNameMatch({ exclude: /^two$/ })
391531
})
392532

533+
test('exclude (regex with a flag)', async () => {
534+
await assertNameMatchWithFlagExclude({ exclude: /one/g })
535+
})
536+
393537
test('exclude (array)', async () => {
394538
await assertNameMatch({ exclude: ['two'] })
395539
})

Diff for: packages/runtime-core/src/components/KeepAlive.ts

+1
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ function matches(pattern: MatchPattern, name: string): boolean {
382382
} else if (isString(pattern)) {
383383
return pattern.split(',').includes(name)
384384
} else if (isRegExp(pattern)) {
385+
pattern.lastIndex = 0
385386
return pattern.test(name)
386387
}
387388
/* istanbul ignore next */

0 commit comments

Comments
 (0)