-
Notifications
You must be signed in to change notification settings - Fork 59
/
lifecycle.js
125 lines (111 loc) · 4.42 KB
/
lifecycle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { last, lensPath, view } from 'ramda';
import { mount as vtuMount } from '@vue/test-utils';
import { noop } from '../../src/util/util';
import vTooltip from '../../src/directives/tooltip';
import createTestContainer from './container';
////////////////////////////////////////////////////////////////////////////////
// MOUNT
/* For many components, it is no longer possible to access global properties
from the vm property of the Vue Test Utils wrapper: see
https://github.com/vuejs/test-utils/issues/2140. In practice, the only global
properties that we try to access in testing are $router and $route. We can
provide access to them by copying $router to each component, then computing
$route based on $router. */
const shadowRouterProps = {
created() {
// eslint-disable-next-line no-self-assign
if (this.$router != null) this.$router = this.$router;
},
computed: {
$route() {
return this.$router != null ? this.$router.currentRoute.value : undefined;
}
}
};
/*
TODO/vue3. Update these comments.
Our mount() function is similar to mount() from Vue Test Utils. It automatically
specifies useful options to Vue Test Utils' mount(). It also accepts additional
options:
- requestData. Passed to setData() before the component is mounted.
*/
export const mount = (component, options = {}) => {
const { container: containerOption, global: g = {}, ...mountOptions } = options;
const container = containerOption != null && containerOption.install != null
? containerOption
: createTestContainer(containerOption);
g.plugins = g.plugins != null ? [container, ...g.plugins] : [container];
g.directives = { tooltip: vTooltip, ...g.directives };
g.mocks = { $container: container, ...g.mocks };
if (g.mixins != null) throw new Error('unexpected mixin');
g.mixins = [shadowRouterProps];
return vtuMount(component, { ...mountOptions, global: g });
};
const optionsToMerge = [
['props'],
['slots'],
['attrs'],
['global'],
['global', 'mocks'],
['global', 'provide'],
['global', 'stubs'],
['container']
];
// Merges two sets of options for mount().
export const mergeMountOptions = (options, defaults) => {
if (options != null && options.container != null && defaults.container != null &&
(options.container.install != null || defaults.container.install != null))
throw new Error('cannot merge container options');
const merged = { ...defaults, ...options };
for (const path of optionsToMerge) {
const viewPath = view(lensPath(path));
const option = options != null ? viewPath(options) : undefined;
const defaultOption = viewPath(defaults);
if (option != null || defaultOption != null) {
const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], merged);
parent[last(path)] = { ...defaultOption, ...option };
}
}
// Merge container.requestData.
if (merged.container != null && merged.container.install == null) {
const option = options != null && options.container != null
? options.container.requestData
: undefined;
const defaultOption = defaults.container != null
? defaults.container.requestData
: undefined;
if (option != null || defaultOption != null) {
if (typeof option !== 'function' && typeof defaultOption !== 'function') {
merged.container.requestData = { ...defaultOption, ...option };
} else if (typeof option === 'function' && typeof defaultOption === 'function') {
throw new Error('cannot merge requestData options');
} else {
const [factory, seedData] = typeof option === 'function'
? [option, defaultOption]
: [defaultOption, option];
merged.container.requestData = seedData == null
? factory
: (container) => {
const requestData = factory(container);
requestData.seed(seedData);
return requestData;
};
}
}
}
return merged;
};
// withSetup() mounts a simple component whose setup() function will call f().
// The component will be mounted with the specified options, after which
// withSetup() will return the return value of f(). withSetup() is a useful way
// to test a composable that uses provide/inject or lifecycle hooks. See:
// https://vuejs.org/guide/scaling-up/testing.html#testing-composables
export const withSetup = (f, options = undefined) => {
let result;
const setup = () => {
result = f();
return noop;
};
mount({ setup }, options);
return result;
};