Strongly type Forms on TaxReturn.
[ustaxlib.git] / src / Line.test.ts
1 import { Line, AccumulatorLine, InputLine, ReferenceLine, ComputedLine } from './Line';
2 import Form, { FormClass } from './Form';
3 import TaxReturn from './TaxReturn';
4 import { NotFoundError } from './Errors';
5
6 class ConstantLine<T> extends Line<T> {
7 private _k: T;
8
9 constructor(k: T) {
10 super(`Constant ${k}`);
11 this._k = k;
12 }
13
14 value(tr: TaxReturn): T {
15 return this._k;
16 }
17 };
18
19 test('computed line', () => {
20 const tr = new TaxReturn(2019);
21 const l = new ComputedLine<number>(
22 (taxReturn: TaxReturn, line: ComputedLine<number>): number => {
23 expect(taxReturn).toBe(tr);
24 expect(line).toBe(l);
25 return 42;
26 },
27 'Computed Line A');
28 expect(l.value(tr)).toBe(42);
29 expect(l.description).toBe('Computed Line A');
30 });
31
32 test('reference line', () => {
33 class TestForm extends Form<TestForm['_lines']> {
34 readonly name = 'Form 1';
35 protected readonly _lines = {
36 '6b': new ConstantLine(12.34),
37 's': new ConstantLine('abc'),
38 };
39 };
40
41 const tr = new TaxReturn(2019);
42 tr.addForm(new TestForm());
43
44 const l1 = new ReferenceLine(TestForm, '6b');
45 let n: number = l1.value(tr);
46 expect(n).toBe(12.34);
47
48 const l2 = new ReferenceLine(TestForm, 's');
49 let s: string = l2.value(tr);
50 expect(s).toBe('abc');
51
52 //TYPEERROR:
53 //const l3 = new ReferenceLine(TestForm, '7a');
54 //let n2: string = l1.value(tr);
55 //let s2: number = l2.value(tr);
56 });
57
58 test('self reference line', () => {
59 class OtherForm extends Form<OtherForm['_lines']> {
60 readonly name = 'Form A';
61 protected readonly _lines = {
62 '6c': new ConstantLine(55)
63 };
64 };
65 class TestForm extends Form<TestForm['_lines']> {
66 readonly name = 'Form 1';
67 protected readonly _lines = {
68 'a': new ConstantLine(100.2),
69 'b': new ReferenceLine(OtherForm, '6c'),
70 'c': new ReferenceLine((TestForm as unknown) as FormClass<Form<any>>, 'b'),
71 'd': new ReferenceLine(TestForm as any, 'b'),
72 };
73 };
74
75 const tr = new TaxReturn(2019);
76 const f = new TestForm();
77 tr.addForm(f);
78 tr.addForm(new OtherForm());
79
80 expect(f.getValue(tr, 'a')).toBe(100.2);
81 expect(f.getValue(tr, 'b')).toBe(55);
82 expect(f.getValue(tr, 'c')).toBe(55);
83 expect(f.getValue(tr, 'd')).toBe(55);
84 });
85
86 test('input line', () => {
87 interface Input {
88 key: string;
89 key2?: string;
90 }
91 class TestForm extends Form<TestForm['_lines'], Input> {
92 readonly name = 'F1';
93 protected readonly _lines = {
94 '1': new InputLine<Input>('key'),
95 '2': new InputLine<Input>('key2')
96 };
97 };
98 const tr = new TaxReturn(2019);
99 const f = new TestForm({ 'key': 'value' });
100 tr.addForm(f);
101
102 expect(f.getLine('1').value(tr)).toBe('value');
103 expect(f.getLine('1').id).toBe('1');
104
105 const l2 = f.getLine('2');
106 expect(() => l2.value(tr)).toThrow(NotFoundError);
107 });
108
109 test('line stack', () => {
110 class FormZ extends Form<FormZ['_lines'], {'input': number}> {
111 readonly name = 'Z';
112 protected readonly _lines = {
113 '3': new InputLine<any, any>('input')
114 }
115 };
116
117 class FormZ2 extends Form<FormZ2['_lines']> {
118 readonly name = 'Z-2';
119 protected readonly _lines = {
120 '2c': new ComputedLine<number>((tr: TaxReturn, l: Line<number>): any => {
121 return tr.getForm(FormZ).getLine('3').value(tr) * 0.2;
122 })
123 };
124 };
125
126 const tr = new TaxReturn(2019);
127 tr.addForm(new FormZ({ 'input': 100 }));
128 tr.addForm(new FormZ2());
129
130 const l = new ReferenceLine(FormZ2, '2c');
131 expect(l.value(tr)).toBe(20);
132 });
133
134 test('accumulator line', () => {
135 class TestForm extends Form<TestForm['_lines']> {
136 readonly name = 'Form B';
137 readonly supportsMultipleCopies = true;
138 protected readonly _lines = {
139 g: new ConstantLine<number>(100.25)
140 };
141 };
142
143 const tr = new TaxReturn(2019);
144 tr.addForm(new TestForm());
145 tr.addForm(new TestForm());
146 tr.addForm(new TestForm());
147
148 const l = new AccumulatorLine(TestForm, 'g');
149 expect(l.value(tr)).toBe(300.75);
150 });