Strongly type Forms on TaxReturn.
[ustaxlib.git] / src / Form.test.ts
1 import { ComputedLine, Line } from './Line';
2 import TaxReturn from './TaxReturn';
3 import Form, { isFormT } from './Form';
4 import { InconsistencyError, NotFoundError } from './Errors';
5
6 test('add and get line', () => {
7 const l = new ComputedLine<number>(() => 42);
8
9 class TestForm extends Form<TestForm['_lines']> {
10 readonly name = 'Test Form';
11
12 protected readonly _lines = { '1': l };
13 };
14
15 const f = new TestForm();
16 expect(f.getLine('1')).toBe(l);
17 });
18
19 test('get non-existent line', () => {
20 class TestForm extends Form<TestForm['_lines']> {
21 readonly name = 'Test';
22 protected readonly _lines = {};
23 };
24
25 const f = new TestForm();
26 const fAsAny: Form<any> = f;
27 expect(() => fAsAny.getLine('line')).toThrow(NotFoundError);
28
29 //TYPEERROR:
30 //expect(() => f.getLine('line')).toThrow(NotFoundError);
31 });
32
33 test('input', () => {
34 interface TestInput {
35 filingStatus: string;
36 money: number;
37 };
38 class TestForm extends Form<any, TestInput> {
39 readonly name = '1040';
40
41 protected readonly _lines = null;
42 };
43
44 const f = new TestForm({ filingStatus: 'S', money: 100.0 });
45 expect(f.getInput('filingStatus')).toBe('S');
46 });
47
48 test('get value', () => {
49 class TestForm extends Form<TestForm['_lines']> {
50 readonly name = 'Form';
51
52 protected readonly _lines = {
53 line: new ComputedLine<number>(() => 42),
54 };
55 };
56
57 const f = new TestForm();
58 const tr = new TaxReturn(2019);
59 expect(f.getValue(tr, 'line')).toBe(42);
60
61 //TYPEERROR:
62 //let s: string = f.getValue(tr, 'line');
63
64 const fAsAny: Form<any> = f;
65 expect(() => fAsAny.getValue(tr, 'other')).toThrow(NotFoundError);
66 //TYPEERROR:
67 //expect(() => f.getValue(tr, 'other')).toThrow(NotFoundError);
68 });
69
70 test('form types', () => {
71 class FormA extends Form<any> {
72 readonly name = 'A';
73 protected readonly _lines = {};
74 };
75 class FormB extends Form<any> {
76 readonly name = 'B';
77 protected readonly _lines = {};
78 };
79
80 expect(isFormT(new FormA(), FormA)).toBe(true);
81 expect(isFormT(new FormB(), FormA)).toBe(false);
82 expect(isFormT(new FormA(), FormB)).toBe(false);
83 expect(isFormT(new FormB(), FormB)).toBe(true);
84 });
85
86 /*
87 abstract class Form2<L extends { [key: string]: Line<any> } , I> {
88 abstract readonly name: string;
89
90 protected abstract readonly _lines: L;
91 protected abstract readonly _input?: I;
92
93 getLine<K extends keyof L>(key: K): L[K] {
94 return this._lines[key];
95 }
96
97 getInput<K extends keyof I>(key: K): I[K] {
98 return this._input[key];
99 }
100
101 getValue<T, K extends keyof L>(tr: TaxReturn, key: K): T {
102 const line = this.getLine(key);
103 return line.value(tr);
104 }
105 };
106
107 class FormG extends Form2<FormG['_lines'], FormG['_input']> {
108 readonly name = 'G';
109
110 protected readonly _lines = {
111 x: new ComputedLine('moo', () => 42),
112 z: new ComputedLine('moo', () => 36),
113 };
114 protected readonly _input = null;
115
116 private _moo = 42;
117
118 getLineImpl<T, K extends keyof T>(lines: T, k: K): T[K] {
119 return lines[k];
120 }
121
122 allLines(): FormG['_lines'] {
123 return this._lines;
124 }
125
126 LINE = k => this.getLineImpl(this._lines, k);
127
128 testLine<K extends keyof ReturnType<FormG['allLines']>>(k: K): any {
129 return this.getLineImpl(this._lines, k);
130 }
131 }
132
133 test('testing', () => {
134 const g = new FormG();
135 let v = g.testLine('x'); //g.getLineImpl(g._lines, 'x');
136 let v2 = g.getValue(null, 'z');
137 throw new Error(`v = ${v2}`);
138 });
139 */