Skip to content

Commit 0ef3ed4

Browse files
committed
refactor(createPlugin): add tests, improve doc blocks
1 parent a68ae37 commit 0ef3ed4

File tree

2 files changed

+193
-6
lines changed

2 files changed

+193
-6
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// Factories
2+
import { createApp } from 'vue'
3+
import { createPlugin } from './index'
4+
5+
// Utilities
6+
import { describe, it, expect, vi, beforeEach } from 'vitest'
7+
8+
// Types
9+
import type { App } from 'vue'
10+
import type { PluginOptions } from './index'
11+
12+
interface TestPlugin {
13+
install: (app: App) => void
14+
}
15+
16+
describe('createPlugin', () => {
17+
let mockApp: App
18+
let mockRunWithContext: ReturnType<typeof vi.fn>
19+
let mockProvide: ReturnType<typeof vi.fn>
20+
let mockSetup: ReturnType<typeof vi.fn>
21+
22+
beforeEach(() => {
23+
mockRunWithContext = vi.fn(callback => callback())
24+
mockApp = {
25+
runWithContext: mockRunWithContext,
26+
} as any
27+
28+
mockProvide = vi.fn()
29+
mockSetup = vi.fn()
30+
})
31+
32+
it('should return a plugin object with install method', () => {
33+
const options: PluginOptions = {
34+
namespace: 'test',
35+
provide: mockProvide,
36+
}
37+
38+
const plugin = createPlugin<TestPlugin>(options)
39+
40+
expect(plugin).toHaveProperty('install')
41+
expect(typeof plugin.install).toBe('function')
42+
})
43+
44+
it('should call app.runWithContext when installing', () => {
45+
const options: PluginOptions = {
46+
namespace: 'test',
47+
provide: mockProvide,
48+
}
49+
50+
const plugin = createPlugin<TestPlugin>(options)
51+
plugin.install(mockApp)
52+
53+
expect(mockRunWithContext).toHaveBeenCalledOnce()
54+
expect(mockRunWithContext).toHaveBeenCalledWith(expect.any(Function))
55+
})
56+
57+
it('should call provide function during installation', () => {
58+
const options: PluginOptions = {
59+
namespace: 'test',
60+
provide: mockProvide,
61+
}
62+
63+
const plugin = createPlugin<TestPlugin>(options)
64+
plugin.install(mockApp)
65+
66+
expect(mockProvide).toHaveBeenCalledOnce()
67+
expect(mockProvide).toHaveBeenCalledWith(mockApp)
68+
})
69+
70+
it('should call setup function when provided', () => {
71+
const options: PluginOptions = {
72+
namespace: 'test',
73+
provide: mockProvide,
74+
setup: mockSetup,
75+
}
76+
77+
const plugin = createPlugin<TestPlugin>(options)
78+
plugin.install(mockApp)
79+
80+
expect(mockSetup).toHaveBeenCalledOnce()
81+
expect(mockSetup).toHaveBeenCalledWith(mockApp)
82+
})
83+
84+
it('should not call setup function when not provided', () => {
85+
const options: PluginOptions = {
86+
namespace: 'test',
87+
provide: mockProvide,
88+
}
89+
90+
const plugin = createPlugin<TestPlugin>(options)
91+
plugin.install(mockApp)
92+
93+
expect(mockSetup).not.toHaveBeenCalled()
94+
})
95+
96+
it('should handle async setup function', async () => {
97+
const asyncSetup = vi.fn().mockResolvedValue(undefined)
98+
const options: PluginOptions = {
99+
namespace: 'test',
100+
provide: mockProvide,
101+
setup: asyncSetup,
102+
}
103+
104+
const plugin = createPlugin<TestPlugin>(options)
105+
plugin.install(mockApp)
106+
107+
expect(asyncSetup).toHaveBeenCalledOnce()
108+
expect(asyncSetup).toHaveBeenCalledWith(mockApp)
109+
})
110+
111+
it('should work with different namespace values', () => {
112+
const namespaces = ['my-plugin', 'custom-namespace', 'vuetify-component']
113+
114+
for (const namespace of namespaces) {
115+
const options: PluginOptions = {
116+
namespace,
117+
provide: mockProvide,
118+
}
119+
120+
const plugin = createPlugin<TestPlugin>(options)
121+
122+
expect(plugin).toHaveProperty('install')
123+
expect(typeof plugin.install).toBe('function')
124+
}
125+
})
126+
127+
it('should maintain execution order: provide then setup', () => {
128+
const executionOrder: string[] = []
129+
130+
const orderTrackingProvide = vi.fn(() => {
131+
executionOrder.push('provide')
132+
})
133+
134+
const orderTrackingSetup = vi.fn(() => {
135+
executionOrder.push('setup')
136+
})
137+
138+
const options: PluginOptions = {
139+
namespace: 'test',
140+
provide: orderTrackingProvide,
141+
setup: orderTrackingSetup,
142+
}
143+
144+
const plugin = createPlugin<TestPlugin>(options)
145+
plugin.install(mockApp)
146+
147+
expect(executionOrder).toEqual(['provide', 'setup'])
148+
})
149+
150+
it('should work with generic type parameter', () => {
151+
interface CustomPlugin {
152+
install: (app: App) => void
153+
customMethod?: () => string
154+
}
155+
156+
const options: PluginOptions = {
157+
namespace: 'typed-plugin',
158+
provide: mockProvide,
159+
}
160+
161+
const plugin = createPlugin<CustomPlugin>(options)
162+
163+
// TypeScript should understand this as CustomPlugin type
164+
expect(plugin).toHaveProperty('install')
165+
expect(typeof plugin.install).toBe('function')
166+
})
167+
168+
it('should integrate with real Vue app', () => {
169+
const realApp = createApp({})
170+
const realProvide = vi.fn()
171+
const realSetup = vi.fn()
172+
173+
const options: PluginOptions = {
174+
namespace: 'real-test',
175+
provide: realProvide,
176+
setup: realSetup,
177+
}
178+
179+
const plugin = createPlugin<TestPlugin>(options)
180+
181+
expect(() => {
182+
plugin.install(realApp)
183+
}).not.toThrow()
184+
185+
expect(realProvide).toHaveBeenCalledWith(realApp)
186+
expect(realSetup).toHaveBeenCalledWith(realApp)
187+
})
188+
})

packages/0/src/factories/createPlugin/index.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ export interface PluginOptions {
77
setup?: (app: App) => void | Promise<void>
88
}
99

10-
export type { Plugin } from 'vue'
11-
1210
/**
13-
* Universal plugin factory that eliminates boilerplate code for Vue plugin creation.
14-
* This factory standardizes the plugin installation pattern across all composables.
11+
* A universal plugin factory to reduce boilerplate code for Vue plugin creation.
12+
* @param options Configurable object with namespace and provide/setup methods.
13+
* @returns A Vue plugin object with install method that runs app w/ context.
1514
*
16-
* @param options Configuration object with namespace, provide function, and optional setup function
17-
* @returns A Vue plugin object with install method
15+
* @see https://vuejs.org/api/application.html#app-runwithcontext
16+
* @see https://0.vuetifyjs.com/factories/create-plugin
1817
*/
1918
export function createPlugin<Z> (options: PluginOptions) {
2019
return {

0 commit comments

Comments
 (0)