Skip to content

Commit cc958a9

Browse files
committed
chore: cover v7 changes — compat fallback exempt from coverage, add state/events/composer tests
1 parent c630a5a commit cc958a9

4 files changed

Lines changed: 160 additions & 0 deletions

File tree

‎src/compat.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ export const makeObservable = (target: any, annotations: Annotations): any => {
3737
return M.makeObservable(target, annotations);
3838
}
3939

40+
return fallbackMakeObservable(target, annotations);
41+
};
42+
43+
/* istanbul ignore next -- MobX 5 only: no makeObservable in 5.x and no decorate in 6/7, not runnable on the MobX 6/7 test matrix */
44+
function fallbackMakeObservable(target: any, annotations: Annotations): any {
4045
const members = Object.entries(annotations).filter(([key]) =>
4146
key in target
4247
);

‎tests/unit/test.composer.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,27 @@ describe("Composer", () => {
179179
expect(wizard.select("step1").isPristine).to.be.true;
180180
expect(wizard.select("step2").isPristine).to.be.true;
181181
});
182+
183+
it("should accept explicit option objects for clear/reset (default-arg branches)", () => {
184+
const wizard = buildWizard();
185+
186+
wizard.select("step1").$("email").value = "test@test.com";
187+
188+
expect(() => wizard.clear({ deep: false })).to.not.throw();
189+
expect(() => wizard.reset({ deep: true, execHook: true })).to.not.throw();
190+
191+
expect(wizard.get("value").step1.email).to.equal("");
192+
});
193+
194+
it("should accept explicit option objects for validate/submit (default-arg branches)", () => {
195+
const wizard = buildWizard();
196+
197+
return wizard
198+
.validate({ showErrors: false })
199+
.then(() => wizard.submit({ validate: false, execOnSubmitHook: true, execValidationHooks: true }))
200+
.then((result: any) => {
201+
expect(result.valid).to.be.false;
202+
expect(result.error).to.be.true;
203+
});
204+
});
182205
});

‎tests/unit/test.events.field.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,29 @@ describe("Field Event Handlers", () => {
238238
expect(field.files).to.have.lengthOf(1);
239239
expect(field.files[0]).to.deep.equal(file);
240240
});
241+
242+
it("should dedupe repeated drops of the same file (FIXES row 28)", () => {
243+
const fileA = { name: "a.txt", size: 10, lastModified: 1700000000000 };
244+
const fileB = { name: "b.txt", size: 20, lastModified: 1700000000001 };
245+
246+
field.onDrop(fileA);
247+
field.onDrop({ ...fileA });
248+
field.onDrop(fileB);
249+
250+
expect(field.files).to.have.lengthOf(2);
251+
expect(field.files.map((f: any) => f.name)).to.have.members([
252+
"a.txt",
253+
"b.txt",
254+
]);
255+
});
256+
257+
it("should keep a distinct file whose size differs only in lastModified", () => {
258+
const base = { name: "a.txt", size: 10, lastModified: 1700000000000 };
259+
field.onDrop(base);
260+
field.onDrop({ name: "a.txt", size: 10, lastModified: 1700000000002 });
261+
262+
expect(field.files).to.have.lengthOf(2);
263+
});
241264
});
242265

243266
describe("focus() and blur() actions", () => {

‎tests/unit/test.state.ts‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from "chai";
22
import Form from "../../src/Form";
3+
import vjf from "../../src/validators/VJF";
34
import { StateInterface } from "../../src/models/StateInterface";
45

56
describe("State — extra() coverage", () => {
@@ -172,3 +173,111 @@ describe("State — observeOptions exec callbacks", () => {
172173
expect(form.state.options.get("validateOnChange")).to.be.false;
173174
});
174175
});
176+
177+
describe("State — set() current subtype", () => {
178+
it("should assign only the current subtype (not initial)", () => {
179+
const form = new Form({
180+
fields: { k: { label: "K", value: "v" } },
181+
});
182+
const state: any = (form as any).state;
183+
184+
state.set("current", "props", { marker: "current-only" });
185+
186+
expect(state.current.props.marker).to.equal("current-only");
187+
expect(state.initial.props.marker).to.be.undefined;
188+
});
189+
});
190+
191+
describe("State — dispose guards on fields without observers", () => {
192+
it("validateOnChange -> false skips fields without disposeValidationOnChange", () => {
193+
const form = new Form(
194+
{
195+
fields: {
196+
email: {
197+
label: "Email",
198+
value: "x",
199+
rules: "required",
200+
options: { validateOnChange: false } as any,
201+
},
202+
},
203+
},
204+
{ name: "Guard1", options: { validateOnChange: true } as any }
205+
);
206+
207+
expect(() =>
208+
form.state.options.set({ validateOnChange: false })
209+
).to.not.throw();
210+
expect(form.state.options.get("validateOnChange")).to.be.false;
211+
});
212+
213+
it("validateOnBlur -> false skips fields without disposeValidationOnBlur", () => {
214+
const form = new Form(
215+
{
216+
fields: {
217+
email: {
218+
label: "Email",
219+
value: "x",
220+
rules: "required",
221+
options: { validateOnBlur: false } as any,
222+
},
223+
},
224+
},
225+
{ name: "Guard2", options: { validateOnBlur: true } as any }
226+
);
227+
228+
expect(() =>
229+
form.state.options.set({ validateOnBlur: false })
230+
).to.not.throw();
231+
expect(form.state.options.get("validateOnBlur")).to.be.false;
232+
});
233+
});
234+
235+
describe("Form — deep showErrors() and resetValidation()", () => {
236+
it("should propagate deep and accept shallow flag", async () => {
237+
const form = new Form(
238+
{
239+
fields: {
240+
email: {
241+
label: "Email",
242+
value: "",
243+
validators: [
244+
({ field }: any) => (field.value ? true : "Email required"),
245+
],
246+
},
247+
nested: {
248+
fields: [
249+
{
250+
name: "user",
251+
label: "User",
252+
value: "",
253+
validators: [
254+
({ field }: any) => (field.value ? true : "User required"),
255+
],
256+
},
257+
],
258+
},
259+
},
260+
},
261+
{
262+
name: "Deep",
263+
plugins: { vjf: vjf() },
264+
options: { validateOnInit: false } as any,
265+
}
266+
);
267+
268+
await form.validate({ showErrors: false });
269+
270+
expect(form.hasError).to.be.true;
271+
272+
form.showErrors(true);
273+
expect(form.$("email").hasError).to.be.true;
274+
275+
form.showErrors(false);
276+
expect(form.$("email").hasError).to.be.true;
277+
278+
form.resetValidation();
279+
form.resetValidation(false);
280+
expect(form.validator.error).to.be.null;
281+
expect(form.$("email").error).to.be.null;
282+
});
283+
});

0 commit comments

Comments
 (0)