Skip to content

Commit 53e2733

Browse files
committed
more ipf tests
1 parent ca8b534 commit 53e2733

File tree

3 files changed

+217
-45
lines changed

3 files changed

+217
-45
lines changed

src/fields/inputFields/AbstractInputField.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
1010
readonly base: IInputFieldBase;
1111
readonly inputFieldComponent: InputFieldComponent<ComponentValueType>;
1212
readonly inputSignal: Signal<unknown>;
13-
readonly signal: ComputedSignal<unknown, MetadataValueType>;
13+
readonly computedSignal: ComputedSignal<unknown, MetadataValueType>;
1414

1515
private metadataSubscription?: MetadataSubscription;
1616

@@ -19,45 +19,20 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
1919
this.inputSignal = new Signal<unknown>(undefined);
2020
this.inputFieldComponent = new InputFieldComponent<ComponentValueType>(this.getSvelteComponent());
2121

22-
this.signal = new ComputedSignal<unknown, MetadataValueType>(
22+
this.computedSignal = new ComputedSignal<unknown, MetadataValueType>(
2323
this.inputSignal,
2424
(value: unknown): MetadataValueType => {
2525
const filteredValue = this.filterValue(value);
2626
return filteredValue ?? this.getDefaultValue();
2727
},
2828
);
29-
30-
this.signal.registerListener({
31-
callback: value => this.inputFieldComponent.setValue(this.reverseMapValue(value)),
32-
});
33-
34-
const fullBindTarget = this.base.getFullBindTarget();
35-
36-
if (fullBindTarget) {
37-
this.inputFieldComponent.registerListener({
38-
callback: value => {
39-
// console.log('input field component change', value);
40-
this.notifySubscription(this.mapValue(value));
41-
},
42-
});
43-
44-
this.metadataSubscription = this.base.plugin.metadataManager.subscribe(
45-
this.base.getUuid(),
46-
this.inputSignal,
47-
fullBindTarget,
48-
() => this.base.unload(),
49-
);
50-
}
5129
}
5230

5331
public destroy(): void {
5432
// we don't need to unregister the listener because the component will destroy all listeners on unmount
55-
5633
if (this.inputFieldComponent.isMounted()) {
5734
this.unmount();
5835
}
59-
60-
this.metadataSubscription?.unsubscribe();
6136
}
6237

6338
protected abstract getSvelteComponent(): typeof SvelteComponent;
@@ -100,7 +75,7 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
10075
* Get the metadata value that the input field currently has.
10176
*/
10277
public getValue(): MetadataValueType {
103-
return this.signal.get();
78+
return this.computedSignal.get();
10479
}
10580

10681
/**
@@ -116,7 +91,7 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
11691
* @param value
11792
*/
11893
public setValue(value: MetadataValueType): void {
119-
this.signal.set(value);
94+
this.computedSignal.set(value);
12095
this.notifySubscription(value);
12196
}
12297

@@ -133,7 +108,7 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
133108
this.metadataSubscription?.update(value);
134109
}
135110

136-
private getDefaultValue(): MetadataValueType {
111+
public getDefaultValue(): MetadataValueType {
137112
const defaultValueArgument = this.base.getArgument(InputFieldArgumentType.DEFAULT_VALUE);
138113
if (!defaultValueArgument) {
139114
return this.mapValue(this.getFallbackDefaultValue());
@@ -147,10 +122,35 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
147122
}
148123

149124
public mount(container: HTMLElement): void {
125+
this.computedSignal.registerListener({
126+
callback: value => this.inputFieldComponent.setValue(this.reverseMapValue(value)),
127+
});
128+
129+
const fullBindTarget = this.base.getFullBindTarget();
130+
131+
if (fullBindTarget) {
132+
this.inputFieldComponent.registerListener({
133+
callback: value => {
134+
// console.log('input field component change', value);
135+
this.notifySubscription(this.mapValue(value));
136+
},
137+
});
138+
139+
this.metadataSubscription = this.base.plugin.metadataManager.subscribe(
140+
this.base.getUuid(),
141+
this.inputSignal,
142+
fullBindTarget,
143+
() => this.base.unload(),
144+
);
145+
}
146+
150147
this.inputFieldComponent.mount(container, this.reverseMapValue(this.getValue()), this.getMountArgs());
151148
}
152149

153150
public unmount(): void {
151+
this.computedSignal.listeners = [];
152+
this.metadataSubscription?.unsubscribe();
153+
154154
this.inputFieldComponent.unmount();
155155
}
156156

tests/fields/inputFields/ToggleIPF.test.ts

Lines changed: 182 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,181 @@
1-
import { beforeEach, describe, expect, spyOn, test } from 'bun:test';
1+
import { beforeEach, describe, expect, test } from 'bun:test';
22
import { TestPlugin } from '../../mocks/TestAPI';
3-
import { ToggleIPF } from '../../../src/fields/inputFields/fields/Toggle/ToggleIPF';
4-
import { RenderChildType } from '../../../src/config/FieldConfigs';
3+
import { InputFieldType, RenderChildType } from '../../../src/config/FieldConfigs';
54
import { TestIPFBase } from '../../mocks/TestIPFBase';
65
import { Metadata } from '../../../src/metadata/MetadataManagerCacheItem';
76
import { Signal } from '../../../src/utils/Signal';
87
import { getUUID } from '../../../src/utils/Utils';
98
import { parsePropPath } from '../../../src/utils/prop/PropParser';
9+
import { InputField } from '../../../src/fields/inputFields/InputFieldFactory';
1010

1111
const TEST_FILE_PATH = 'testFile';
1212
const TEST_PROP = 'testProp';
1313

14-
describe('ToggleIPF test', () => {
14+
const TEST_VALUES = {
15+
UNDEFINED: undefined,
16+
NULL: null,
17+
18+
EMPTY_STRING: '',
19+
STRING: 'string',
20+
21+
TRUE: true,
22+
FALSE: false,
23+
24+
BOOLEAN_STRING_TURE: 'true',
25+
BOOLEAN_STRING_TURE_CAPITAL: 'True',
26+
BOOLEAN_STRING_TURE_CAPITAL_2: 'TRUE',
27+
BOOLEAN_STRING_FALSE: 'false',
28+
BOOLEAN_STRING_FALSE_CAPITAL: 'False',
29+
BOOLEAN_STRING_FALSE_CAPITAL_2: 'FALSE',
30+
31+
POSITIVE_INT: 123,
32+
NEGATIVE_INT: -123,
33+
POSITIVE_FLOAT: 123.456,
34+
NEGATIVE_FLOAT: -123.456,
35+
36+
POSITIVE_NUMBER_STRING: '123',
37+
NEGATIVE_NUMBER_STRING: '-123',
38+
POSITIVE_FLOAT_STRING: '123.456',
39+
NEGATIVE_FLOAT_STRING: '-123.456',
40+
41+
EMPTY_OBJECT: {},
42+
OBJECT: { a: 1, b: 2 },
43+
44+
EMPTY_ARRAY: [],
45+
ARRAY: [1, 2, 3],
46+
} as const;
47+
48+
interface IPFTest {
49+
type: InputFieldType;
50+
declaration: string;
51+
exampleValues?: any[];
52+
}
53+
54+
const STANDARD_OPTION_VALUES = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
55+
const STANDARD_OPTION_ARGUMENTS = STANDARD_OPTION_VALUES.map(x => `option(${x})`).join(', ');
56+
const STANDARD_OPTION_VALUES_ARRAY = [['a', 'b'], ['c', 'd', 'e'], ['f', 'g', 'h', 'i'], ['j']];
57+
58+
let TEST_CONFIG: IPFTest[] = [
59+
{
60+
type: InputFieldType.TOGGLE,
61+
declaration: `INPUT[${InputFieldType.TOGGLE}:${TEST_PROP}]`,
62+
exampleValues: [true, false],
63+
},
64+
{
65+
type: InputFieldType.SLIDER,
66+
declaration: `INPUT[${InputFieldType.SLIDER}:${TEST_PROP}]`,
67+
exampleValues: [0, 1, 2, 3, 4, 5],
68+
},
69+
{
70+
type: InputFieldType.TEXT,
71+
declaration: `INPUT[${InputFieldType.TEXT}:${TEST_PROP}]`,
72+
exampleValues: [TEST_VALUES.EMPTY_STRING, TEST_VALUES.STRING],
73+
},
74+
{
75+
type: InputFieldType.TEXT_AREA,
76+
declaration: `INPUT[${InputFieldType.TEXT_AREA}:${TEST_PROP}]`,
77+
exampleValues: [TEST_VALUES.EMPTY_STRING, TEST_VALUES.STRING],
78+
},
79+
{
80+
type: InputFieldType.SELECT,
81+
declaration: `INPUT[${InputFieldType.SELECT}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
82+
exampleValues: STANDARD_OPTION_VALUES,
83+
},
84+
{
85+
type: InputFieldType.MULTI_SELECT,
86+
declaration: `INPUT[${InputFieldType.MULTI_SELECT}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
87+
exampleValues: STANDARD_OPTION_VALUES_ARRAY,
88+
},
89+
{
90+
type: InputFieldType.DATE_PICKER,
91+
declaration: `INPUT[${InputFieldType.DATE_PICKER}:${TEST_PROP}]`,
92+
exampleValues: ['2021-01-01', '2021-01-02', '2021-01-03'],
93+
},
94+
{
95+
type: InputFieldType.NUMBER,
96+
declaration: `INPUT[${InputFieldType.NUMBER}:${TEST_PROP}]`,
97+
exampleValues: [0, 1, 2, 3, 4, 5],
98+
},
99+
{
100+
type: InputFieldType.SUGGESTER,
101+
declaration: `INPUT[${InputFieldType.SUGGESTER}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
102+
exampleValues: STANDARD_OPTION_VALUES,
103+
},
104+
{
105+
type: InputFieldType.EDITOR,
106+
declaration: `INPUT[${InputFieldType.EDITOR}:${TEST_PROP}]`,
107+
exampleValues: [TEST_VALUES.EMPTY_STRING, TEST_VALUES.STRING],
108+
},
109+
{
110+
type: InputFieldType.PROGRESS_BAR,
111+
declaration: `INPUT[${InputFieldType.PROGRESS_BAR}:${TEST_PROP}]`,
112+
exampleValues: [0, 1, 2, 3, 4, 5],
113+
},
114+
{
115+
type: InputFieldType.INLINE_SELECT,
116+
declaration: `INPUT[${InputFieldType.INLINE_SELECT}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
117+
exampleValues: STANDARD_OPTION_VALUES,
118+
},
119+
{
120+
type: InputFieldType.IMAGE_SUGGESTER,
121+
declaration: `INPUT[${InputFieldType.IMAGE_SUGGESTER}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
122+
// exampleValues: STANDARD_OPTION_VALUES, // TODO: fix image to uri app not found
123+
},
124+
{
125+
type: InputFieldType.LIST,
126+
declaration: `INPUT[${InputFieldType.LIST}:${TEST_PROP}]`,
127+
exampleValues: STANDARD_OPTION_VALUES_ARRAY,
128+
},
129+
{
130+
type: InputFieldType.LIST_SUGGESTER,
131+
declaration: `INPUT[${InputFieldType.LIST_SUGGESTER}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
132+
exampleValues: STANDARD_OPTION_VALUES_ARRAY,
133+
},
134+
{
135+
type: InputFieldType.DATE,
136+
declaration: `INPUT[${InputFieldType.DATE}:${TEST_PROP}]`,
137+
exampleValues: ['2021-01-01', '2021-01-02', '2021-01-03'],
138+
},
139+
{
140+
type: InputFieldType.TIME,
141+
declaration: `INPUT[${InputFieldType.TIME}:${TEST_PROP}]`,
142+
exampleValues: ['14:45', '05:03'],
143+
},
144+
{
145+
type: InputFieldType.INLINE_LIST_SUGGESTER,
146+
declaration: `INPUT[${InputFieldType.INLINE_LIST_SUGGESTER}(${STANDARD_OPTION_ARGUMENTS}):${TEST_PROP}]`,
147+
exampleValues: STANDARD_OPTION_VALUES_ARRAY,
148+
},
149+
{
150+
type: InputFieldType.INLINE_LIST,
151+
declaration: `INPUT[${InputFieldType.INLINE_LIST}:${TEST_PROP}]`,
152+
exampleValues: STANDARD_OPTION_VALUES_ARRAY,
153+
},
154+
];
155+
156+
describe('IPF', () => {
15157
let testPlugin: TestPlugin;
16158
let ipfBase: TestIPFBase;
17-
let toggleIPF: ToggleIPF;
159+
let ipf: InputField;
160+
161+
beforeEach(() => {});
18162

19-
beforeEach(() => {
163+
/**
164+
* Set up the test by setting the initial metadata and loading the input field.
165+
*
166+
* @param testCase
167+
* @param initialMetadata the initial metadata to set, will not set any metadata and will not create a cache item for the test file if undefined
168+
*/
169+
function setup(testCase: IPFTest, initialMetadata?: Record<string, unknown> | undefined): void {
20170
testPlugin = new TestPlugin();
171+
21172
ipfBase = testPlugin.api.createInputFieldFromString(
22-
`INPUT[toggle:${TEST_PROP}]`,
173+
testCase.declaration,
23174
RenderChildType.BLOCK,
24175
TEST_FILE_PATH,
25176
document.body,
26177
);
27-
});
28178

29-
function setup(initialMetadata: Record<string, unknown> | undefined): void {
30179
if (initialMetadata !== undefined) {
31180
// setting the initial metadata only works if the cache is already initialized, which happens when someone subscribes to the file
32181
const subscription = testPlugin.metadataManager.subscribe(
@@ -51,13 +200,31 @@ describe('ToggleIPF test', () => {
51200
);
52201
// load the input field base and save a reference to the inner input field
53202
ipfBase.load();
54-
toggleIPF = ipfBase.inputField as ToggleIPF;
203+
ipf = ipfBase.inputField as InputField;
55204
}
56205

57-
describe('load behaviour', () => {
58-
test('should load and value should be initial front-matter', () => {
59-
setup({ [TEST_PROP]: true });
60-
expect(toggleIPF.getValue()).toBe(true);
206+
for (const TEST_CASE of TEST_CONFIG) {
207+
describe(`${TEST_CASE.type} - ${TEST_CASE.declaration}`, () => {
208+
describe('load behaviour', () => {
209+
// this is also a test that the filter method does not modify the value
210+
describe('should load with front-matter value', () => {
211+
for (const exampleValue of TEST_CASE.exampleValues ?? []) {
212+
test(JSON.stringify(exampleValue), () => {
213+
// add some metadata to the test file and load the input field
214+
setup(TEST_CASE, { [TEST_PROP]: exampleValue });
215+
// check that the input field value is the value of the bound property in the front-matter cache
216+
expect(ipf.getValue()).toEqual(exampleValue);
217+
});
218+
}
219+
});
220+
221+
test('should load with default value when front-matter field not present', () => {
222+
// load the input field without any metadata being set
223+
setup(TEST_CASE);
224+
// check that the input field value is the default value
225+
expect(ipf.getValue()).toEqual(ipf.getDefaultValue());
226+
});
227+
});
61228
});
62-
});
229+
}
63230
});

tests/mocks/TestAPI.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { BindTargetScope } from '../../src/metadata/BindTargetScope';
1414
import { InputFieldDeclaration } from '../../src/parsers/inputFieldParser/InputFieldDeclaration';
1515
import { getUUID } from '../../src/utils/Utils';
1616
import { TestIPFBase } from './TestIPFBase';
17+
import { DateParser } from '../../src/parsers/DateParser';
18+
import { setFirstWeekday } from '../../src/utils/DatePickerUtils';
1719

1820
export class TestPlugin implements IPlugin {
1921
public api: TestAPI;
@@ -29,6 +31,9 @@ export class TestPlugin implements IPlugin {
2931
this.metadataManager = new MetadataManager(metadataAdapter);
3032

3133
this.settings = DEFAULT_SETTINGS;
34+
35+
DateParser.dateFormat = this.settings.preferredDateFormat;
36+
setFirstWeekday(this.settings.firstWeekday);
3237
}
3338

3439
public getFilePathsByName(name: string): string[] {

0 commit comments

Comments
 (0)