This repository has been archived by the owner on Feb 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
formLeaveGuardMixin.test.js
178 lines (151 loc) · 6.21 KB
/
formLeaveGuardMixin.test.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import Vue from "vue";
import { shallowMount } from "@vue/test-utils";
// Utilities
import { FormCreateMixin, FormLeaveGuardMixin } from "../src";
const nextFn = jest.fn();
const onPreventFn = jest.fn();
const Component = Vue.component("formComponent", {
template: "<div />",
});
/**
* Shallow mount a component with the mixin (and custom options)
* @param {string} formKey - Form key
* @param {Object} mixinOptions - Mixin options
* @return - Vue wrapper
*/
const mountComponent = (formKey, mixinOptions = {}) =>
shallowMount(Component, {
mixins: [
// NOTE: Must spread setup values to avoid mutating by reference!
FormCreateMixin(formName, { ...fields }),
FormLeaveGuardMixin(formKey, {
activeKey,
callbackKey,
onPrevent: onPreventFn,
...mixinOptions,
}),
],
});
const formName = "form";
const fields = {
email: "test@example.com",
password: "******",
};
const fieldChanges = {
email: "noone@example.com",
};
const activeKey = "isLeavingForm";
const callbackKey = "onFormLeave";
describe("Form Leave Guard Mixin", () => {
let wrapper = null;
let beforeRouteLeave = null;
// Setup the component with mixin before each test
const beforeHandler = () => {
wrapper = mountComponent(formName);
({ beforeRouteLeave } = wrapper.vm.$options);
};
const afterHandler = () => {
wrapper.destroy();
nextFn.mockReset();
onPreventFn.mockReset();
};
beforeEach(beforeHandler);
afterEach(afterHandler);
it("should run mixin in component", () => {
// Should import successfully
expect(FormLeaveGuardMixin).toBeTruthy();
// Should have active key from mixin options
expect(wrapper.vm[activeKey]).toBe(false);
// Should have callback key from mixin options
expect(wrapper.vm[callbackKey]).toBeNull();
});
it("should handle leaving clean form", () => {
beforeRouteLeave.call(wrapper.vm, "toObj", "fromObj", nextFn);
// Should call "next" when leaving clean form
expect(nextFn).toHaveBeenCalled();
// Should not set active key when leaving clean form
expect(wrapper.vm[activeKey]).toBe(false);
// Should not set callback handler when leaving clean form
expect(wrapper.vm[callbackKey]).toBeNull();
// Should not call custom prevent handler when leaving clean form
expect(onPreventFn).not.toHaveBeenCalled();
});
it("should handle leaving clean forms (multiple)", () => {
const wrapperMulti = mountComponent([formName]);
const beforeRouteLeaveMulti = wrapperMulti.vm.$options.beforeRouteLeave;
beforeRouteLeaveMulti.call(wrapperMulti.vm, "toObj", "fromObj", nextFn);
// Should call "next" when leaving clean forms
expect(nextFn).toHaveBeenCalled();
// Should not set active key when leaving clean forms
expect(wrapperMulti.vm[activeKey]).toBe(false);
// Should not set callback handler when leaving clean forms
expect(wrapperMulti.vm[callbackKey]).toBeNull();
// Should not call custom prevent handler when leaving clean forms
expect(onPreventFn).not.toHaveBeenCalled();
});
describe("should handle leaving dirty form", () => {
beforeEach(() => {
beforeHandler();
// Make changes to form (to trigger "changed" flag)
wrapper.vm[formName].setValues({ ...fieldChanges }, false);
beforeRouteLeave.call(wrapper.vm, "toObj", "fromObj", nextFn);
});
afterEach(afterHandler);
it("should prevent leaving dirty form", async () => {
// Should not call "next" when leaving dirty form
expect(nextFn).not.toHaveBeenCalled();
// Should set "is leaving" active getter
expect(wrapper.vm[activeKey]).toBe(true);
// Should set form leave confirmation callback
expect(wrapper.vm[callbackKey]).not.toBeNull();
// Should remove callback after it is the setter is called (v-model issue)
wrapper.vm[activeKey] = false;
expect(wrapper.vm[callbackKey]).not.toBeNull();
await Vue.nextTick();
expect(wrapper.vm[callbackKey]).toBeNull();
});
it("should remain on dirty form after cancellation", () => {
wrapper.vm[callbackKey]();
// Should reset callback key when staying on dirty form
expect(wrapper.vm[callbackKey]).toBeNull();
// Should not call "next" when staying on dirty form
expect(nextFn).not.toHaveBeenCalled();
});
it("should leave dirty form after confirmation", () => {
wrapper.vm[callbackKey](true);
// Should reset callback key when leaving dirty form
expect(wrapper.vm[callbackKey]).toBeNull();
// Should call "next" when leaving dirty form
expect(nextFn).toHaveBeenCalled();
// Should reset form state when leaving dirty form
expect(wrapper.vm[formName].getValues()).toEqual(fields);
});
it("should leave dirty forms (multiple) after confirmation", () => {
const wrapperMulti = mountComponent([formName]);
const beforeRouteLeaveMulti = wrapperMulti.vm.$options.beforeRouteLeave;
wrapperMulti.vm[formName].setValues({ ...fieldChanges }, false);
beforeRouteLeaveMulti.call(wrapperMulti.vm, "toObj", "fromObj", nextFn);
wrapperMulti.vm[callbackKey](true);
// Should reset callback key when leaving dirty form
expect(wrapperMulti.vm[callbackKey]).toBeNull();
// Should call "next" when leaving dirty form
expect(nextFn).toHaveBeenCalled();
// Should reset form state when leaving dirty form
expect(wrapperMulti.vm[formName].getValues()).toEqual(fields);
});
});
it("should prevent leaving dirty form (without callbacks) if specified", () => {
const wrapperPrevent = mountComponent(formName, {
onlyPrevent: true,
});
const beforeRouteLeavePrevent = wrapperPrevent.vm.$options.beforeRouteLeave;
wrapperPrevent.vm[formName].setValues({ ...fieldChanges }, false);
beforeRouteLeavePrevent.call(wrapperPrevent.vm, "toObj", "fromObj", nextFn);
// Should not call "next" when only preventing leaving dirty form
expect(nextFn).not.toBeCalled();
// Should not set callback when only preventing leaving dirty form
expect(wrapperPrevent.vm[callbackKey]).toBeNull();
// Should call custom prevent handler when only preventing leaving dirty form
expect(onPreventFn).toBeCalled();
});
});