Skip to content

Commit bcfb991

Browse files
Martynas ŽilinskasDovydasNavickas
authored andcommitted
Feature/props in formstore state (#3)
* Added Props to FieldState. * Added props form store tests. * Updated tests (BaseField and FormStore). * Fixed field contracts. * Grammar. * Fixed test form-store.
1 parent 979666a commit bcfb991

File tree

8 files changed

+155
-9
lines changed

8 files changed

+155
-9
lines changed

packages/simplr-forms-core/__tests__/abstractions/base-field.test.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { FormStoresHandlerClass, FSHContainer } from "../../src/stores/form-stor
77
import { FormStore } from "../../src/stores/form-store";
88
import { BasicForm } from "../basic-components/basic-form";
99
import { BasicField } from "../basic-components/basic-field";
10+
import { FormChildContext } from "../../src/contracts/form";
11+
import { MyFieldProps } from "../basic-components/basic-field";
1012

1113
describe("Field Base", () => {
1214
beforeEach(() => {
@@ -205,4 +207,56 @@ describe("Field Base", () => {
205207
// Value should be updated
206208
expect(input.props().value).toEqual(newValue);
207209
});
210+
211+
it("registers and passes props", () => {
212+
const fieldName = "fieldName";
213+
const formId = "form-id";
214+
const fieldProps: MyFieldProps = {
215+
name: fieldName,
216+
value: "initialValue"
217+
};
218+
219+
mount(<BasicForm formId={formId}>
220+
<BasicField {...fieldProps} />
221+
</BasicForm>);
222+
const formStore = FSHContainer.FormStoresHandler.GetStore(formId);
223+
224+
expect((formStore.GetField(fieldName).Props as MyFieldProps).value).toBe(fieldProps.value);
225+
});
226+
227+
it("updates props when componentWillReceiveProps is called", () => {
228+
const formId = "FORM-ID";
229+
const fieldId = "field";
230+
const fieldProps: MyFieldProps = {
231+
name: "field",
232+
value: "initialValue"
233+
};
234+
const fieldPropsNext: MyFieldProps = {
235+
name: fieldProps.name,
236+
value: "Updated value"
237+
};
238+
239+
// Set spies on methods
240+
spy(FormStore.prototype, "UpdateProps");
241+
spy(BasicField.prototype, "componentWillReceiveProps");
242+
243+
// Render form to create FormStore
244+
shallow(<BasicForm formId={formId}></BasicForm>);
245+
246+
const formStore = FSHContainer.FormStoresHandler.GetStore(formId);
247+
248+
// Mount with formId as a context
249+
const field = mount<MyFieldProps>(<BasicField {...fieldProps} />, {
250+
context: {
251+
FormId: formId
252+
} as FormChildContext
253+
});
254+
255+
// Update BasicField props
256+
field.setProps(fieldPropsNext);
257+
258+
expect((FormStore.prototype.UpdateProps as any).callCount).toEqual(1);
259+
expect((BasicField.prototype.componentWillReceiveProps as any).callCount).toEqual(1);
260+
expect((formStore.GetField(fieldId).Props as MyFieldProps).value).toBe(fieldPropsNext.value);
261+
});
208262
});

packages/simplr-forms-core/__tests__/basic-components/basic-field.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import * as React from "react";
33
import { BaseField, BaseFieldState } from "../../src/abstractions/base-field";
44
import { FieldProps, FieldValue } from "../../src/contracts/field";
55

6-
export interface MyFieldProps extends FieldProps { }
6+
export interface MyFieldProps extends FieldProps {
7+
value?: string;
8+
randomKey?: string;
9+
}
710

811
export interface MyFieldState extends BaseFieldState { }
912

packages/simplr-forms-core/__tests__/stores/form-store.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import { recordify } from "typed-immutable-record";
2+
import * as Immutable from "immutable";
3+
14
import { FormStore } from "../../src/stores/form-store";
25
import { FormError } from "../../src/contracts/error";
6+
import { FieldStatePropsRecord, FieldStateProps } from "../../src/contracts/field";
7+
8+
import { MyFieldProps } from "../basic-components/basic-field";
39

410
describe("Form store", () => {
511
it("returns state", () => {
@@ -150,4 +156,46 @@ describe("Form store", () => {
150156
done.fail(error);
151157
}
152158
});
159+
160+
it("registers field with props", () => {
161+
const formId = "FORM-ID";
162+
const fieldId = "FIELD-ID";
163+
const fieldProps: MyFieldProps = {
164+
name: "fieldName",
165+
value: "initial-value",
166+
randomKey: "random value"
167+
};
168+
const formStore = new FormStore(formId);
169+
170+
formStore.RegisterField(fieldId, fieldProps.value, fieldProps);
171+
172+
const fieldPropsRecord = recordify<FieldStateProps, FieldStatePropsRecord>(fieldProps);
173+
174+
// Deep-check the updated props
175+
expect(Immutable.is(formStore.GetField(fieldId).Props, fieldPropsRecord)).toBe(true);
176+
});
177+
178+
it("updates field props", () => {
179+
const formId = "FORM-ID";
180+
const fieldId = "FIELD-ID";
181+
const fieldProps: MyFieldProps = {
182+
name: "field-name",
183+
value: "initialValue",
184+
randomKey: "random value"
185+
};
186+
187+
// Changed value and removed randomKey prop
188+
const fieldPropsNext: MyFieldProps = {
189+
name: fieldProps.name,
190+
value: "Updated value"
191+
};
192+
const fieldPropsNextRecord = recordify<FieldStateProps, FieldStatePropsRecord>(fieldPropsNext);
193+
const formStore = new FormStore(formId);
194+
195+
formStore.RegisterField(fieldId, fieldProps.value, fieldProps);
196+
formStore.UpdateProps(fieldId, fieldPropsNext);
197+
198+
// Deep-check the updated props
199+
expect(Immutable.is(formStore.GetField(fieldId).Props, fieldPropsNextRecord)).toBe(true);
200+
});
153201
});

packages/simplr-forms-core/__tests__/stores/form-stores-handler.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ describe("Form stores handler", () => {
9797
expect(callbackSpy.called).toBe(true);
9898
});
9999

100-
fit("emits unregister action when unregistering a form", () => {
100+
it("emits unregister action when unregistering a form", () => {
101101
const storesHandler = new FormStoresHandlerClass();
102102
const formId = "form-id";
103103
const callbackSpy = sinon.spy();

packages/simplr-forms-core/src/abstractions/base-field.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ export abstract class BaseField<TProps extends FieldProps, TState extends BaseFi
8383
FormStoreActions.StateUpdated,
8484
this.OnStoreUpdated.bind(this));
8585
this.registerFieldInFormStore();
86-
87-
// TODO: Set validators
8886
}
8987

9088
componentWillReceiveProps(nextProps: FieldProps) {
@@ -93,7 +91,7 @@ export abstract class BaseField<TProps extends FieldProps, TState extends BaseFi
9391
throw new Error(`simplr-forms-core: Field name must be constant`);
9492
}
9593

96-
// TODO: Update validators
94+
this.FormStore.UpdateProps(this.FieldId, nextProps);
9795
}
9896

9997
componentWillUnmount() {
@@ -273,6 +271,11 @@ export abstract class BaseField<TProps extends FieldProps, TState extends BaseFi
273271
}
274272

275273
const initialValue = this.RawInitialValue;
276-
this.FormStore.RegisterField(this.FieldId, initialValue, this.FieldsGroupId);
274+
this.FormStore.RegisterField(
275+
this.FieldId,
276+
initialValue,
277+
this.props,
278+
this.FieldsGroupId
279+
);
277280
}
278281
}

packages/simplr-forms-core/src/actions/form-store-actions.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ export class ValueChanged {
77
return this.fieldId;
88
}
99
}
10+
11+
export class PropsChanged {
12+
constructor(private fieldId: string) { }
13+
14+
public get FieldId() {
15+
return this.fieldId;
16+
}
17+
}

packages/simplr-forms-core/src/contracts/field.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export interface FieldProps {
1717
validationType?: FieldValidationType;
1818
onBlur?: (event: any) => void;
1919
onFocus?: (event: any) => void;
20-
children?: React.ReactNode;
2120
}
2221

2322
export interface FieldState {
@@ -30,9 +29,13 @@ export interface FieldState {
3029
FieldsGroup?: {
3130
Id: string;
3231
};
32+
Props?: FieldStatePropsRecord;
3333
}
3434

35+
export type FieldStateProps = FieldProps & React.Props<any>;
36+
3537
export interface FieldStateRecord extends TypedRecord<FieldStateRecord>, FieldState { }
38+
export interface FieldStatePropsRecord extends TypedRecord<FieldStatePropsRecord>, FieldStateProps { }
3639
export interface FormErrorRecord extends TypedRecord<FormErrorRecord>, FormError { }
3740

3841
export enum FieldValidationType {

packages/simplr-forms-core/src/stores/form-store.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import {
77
FieldState,
88
FieldValue,
99
FieldStateRecord,
10-
FormErrorRecord
10+
FormErrorRecord,
11+
FieldProps,
12+
FieldStatePropsRecord,
13+
FieldStateProps
1114
} from "../contracts/field";
1215
import { FormState, FormStateRecord } from "../contracts/form";
1316
import { FormStoreState, FormStoreStateRecord } from "../contracts/form-store";
@@ -64,13 +67,18 @@ export class FormStore extends ActionEmitter {
6467
public RegisterField(
6568
fieldId: string,
6669
initialValue: FieldValue,
70+
props?: FieldProps,
6771
fieldsGroupId?: string
6872
) {
6973
// Construct field state
7074
let fieldState = this.GetInitialFieldState();
7175
fieldState.InitialValue = initialValue;
7276
fieldState.Value = initialValue;
7377

78+
if (props != null) {
79+
fieldState.Props = recordify<FieldStateProps, FieldStatePropsRecord>(props);
80+
}
81+
7482
if (fieldsGroupId != null) {
7583
fieldState.FieldsGroup = {
7684
Id: fieldsGroupId
@@ -98,6 +106,24 @@ export class FormStore extends ActionEmitter {
98106
return this.State.Fields.get(fieldId);
99107
}
100108

109+
public UpdateProps(fieldId: string, props: FieldProps) {
110+
const propsRecord = recordify<FieldStateProps, FieldStatePropsRecord>(props);
111+
const fieldState = this.State.Fields.get(fieldId);
112+
113+
if (fieldState.Props == null || fieldState.Props.equals(propsRecord)) {
114+
return;
115+
}
116+
117+
this.State = this.State.withMutations(state => {
118+
const fieldState = state.Fields.get(fieldId);
119+
state.Fields = state.Fields.set(fieldId, fieldState.merge({
120+
Props: recordify<FieldStateProps, FieldStatePropsRecord>(props)
121+
} as FieldState));
122+
});
123+
124+
this.emit(new Actions.PropsChanged(fieldId));
125+
}
126+
101127
public ValueChanged(fieldId: string, newValue: FieldValue) {
102128
this.emit(new Actions.ValueChanged(fieldId));
103129

@@ -174,7 +200,8 @@ export class FormStore extends ActionEmitter {
174200
Pristine: true,
175201
Validating: false,
176202
Error: undefined,
177-
FieldsGroup: undefined
203+
FieldsGroup: undefined,
204+
Props: undefined
178205
};
179206
}
180207
}

0 commit comments

Comments
 (0)