Add Schedule A for itemized deductions.
[ustaxlib.git] / src / fed2019 / Form1040.test.ts
1 // Copyright 2020 Blue Static <https://www.bluestatic.org>
2 // This program is free software licensed under the GNU General Public License,
3 // version 3.0. The full text of the license can be found in LICENSE.txt.
4 // SPDX-License-Identifier: GPL-3.0-only
5
6 import { Person } from '../core';
7 import { NotFoundError } from '../core/Errors';
8
9 import Form1040, { FilingStatus } from './Form1040';
10 import Form1099DIV from './Form1099DIV';
11 import Form1099INT from './Form1099INT';
12 import Form1099B from './Form1099B';
13 import Form1099R, { Box7Code } from './Form1099R';
14 import Schedule2 from './Schedule2';
15 import ScheduleA from './ScheduleA';
16 import ScheduleD, { ScheduleDTaxWorksheet } from './ScheduleD';
17 import Form8606 from './Form8606';
18 import Form8959 from './Form8959';
19 import Form8949 from './Form8949';
20 import TaxReturn from './TaxReturn';
21 import W2 from './W2';
22
23 test('w2 wages', () => {
24 const pa = Person.self('A');
25 const pb = Person.spouse('B');
26 const tr = new TaxReturn();
27 tr.addPerson(pa);
28 tr.addPerson(pb);
29 tr.addForm(new W2({
30 employer: 'AA',
31 employee: pa,
32 wages: 130000.00,
33 fedIncomeTax: 0,
34 medicareWages: 0,
35 }));
36 tr.addForm(new W2({
37 employer: 'BB',
38 employee: pb,
39 wages: 36.32,
40 fedIncomeTax: 0,
41 medicareWages: 0,
42 }));
43 const f1040 = new Form1040({ filingStatus: FilingStatus.MarriedFilingJoint });
44 tr.addForm(f1040);
45 tr.addForm(new Schedule2);
46 expect(f1040.getValue(tr, '1')).toBe(130036.32);
47 f1040.getValue(tr, '23');
48 });
49
50 test('interest income', () => {
51 const p = Person.self('A');
52 const tr = new TaxReturn();
53 tr.addPerson(p);
54 tr.addForm(new Form1099INT({
55 payer: 'Bank',
56 payee: p,
57 interest: 100,
58 taxExemptInterest: 0,
59 interestOnUsSavingsBondOrTreas: 30
60 }));
61 tr.addForm(new Form1099INT({
62 payer: 'Bank 2',
63 payee: p,
64 interest: 3.50,
65 taxExemptInterest: 95
66 }));
67
68 const f1040 = new Form1040();
69 tr.addForm(f1040);
70
71 expect(f1040.getValue(tr, '2a')).toBe(95);
72 expect(f1040.getValue(tr, '2b')).toBe(133.5);
73 });
74
75 test('dividend income', () => {
76 const p = Person.self('A');
77 const tr = new TaxReturn();
78 tr.addPerson(p);
79 const f1099div = new Form1099DIV({
80 payer: 'Brokerage',
81 payee: p,
82 ordinaryDividends: 100,
83 qualifiedDividends: 75,
84 totalCapitalGain: 100
85 });
86 tr.addForm(f1099div);
87 tr.addForm(f1099div);
88
89 const f1040 = new Form1040();
90 tr.addForm(f1040);
91
92 expect(f1040.getValue(tr, '3a')).toBe(75 * 2);
93 expect(f1040.getValue(tr, '3b')).toBe(200);
94 });
95
96 test('tax-exempt interest', () => {
97 const p = Person.self('A');
98 const tr = new TaxReturn();
99 tr.addPerson(p);
100 tr.addForm(new Form1099DIV({
101 payer: 'Brokerage',
102 payee: p,
103 exemptInterestDividends: 100,
104 }));
105 tr.addForm(new Form1099INT({
106 payer: 'Bank',
107 payee: p,
108 interest: 0,
109 taxExemptInterest: 50
110 }));
111
112 const f1040 = new Form1040();
113 tr.addForm(f1040);
114
115 expect(f1040.getValue(tr, '2a')).toBe(150);
116 });
117
118 test('capital gain/loss', () => {
119 const p = Person.self('A');
120 const tr = new TaxReturn();
121 tr.addPerson(p);
122 tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
123 tr.addForm(new W2({
124 employer: 'Money',
125 employee: p,
126 wages: 150000
127 }));
128 tr.addForm(new Form1099B({
129 payer: 'Brokerage',
130 payee: p,
131 longTermBasisReported: [
132 {
133 description: '10 FNDC',
134 proceeds: 1000,
135 costBasis: 800,
136 }
137 ]
138 }));
139 tr.addForm(new Form8949);
140 tr.addForm(new ScheduleD());
141 tr.addForm(new ScheduleDTaxWorksheet());
142 tr.getForm(ScheduleD).getValue(tr, '21');
143 tr.getForm(Form1040).getValue(tr, '12a');
144 });
145
146 test('require Form8959', () => {
147 const p = Person.self('A');
148 const tr = new TaxReturn();
149 tr.addPerson(p);
150 tr.addForm(new W2({
151 employer: 'Company',
152 employee: p,
153 wages: 400000,
154 }));
155 const f1040 = new Form1040({
156 filingStatus: FilingStatus.MarriedFilingSeparate,
157 });
158 tr.addForm(f1040);
159 tr.addForm(new Schedule2);
160
161 expect(() => f1040.getValue(tr, '15')).toThrow(NotFoundError);
162 expect(() => f1040.getValue(tr, '15')).toThrow('Form8959');
163 expect(f1040.getValue(tr, '1')).toBe(400000);
164 expect(f1040.getValue(tr, '8b')).toBe(400000);
165 });
166
167 test('backdoor and megabackdoor roth', () => {
168 const p = Person.self('A');
169 const tr = new TaxReturn();
170 tr.addPerson(p);
171 tr.addForm(new Form1099R({
172 payer: 'Roth',
173 payee: p,
174 grossDistribution: 6000,
175 taxableAmount: 6000,
176 taxableAmountNotDetermined: true,
177 totalDistribution: true,
178 fedIncomeTax: 0,
179 distributionCodes: [Box7Code._2],
180 iraSepSimple: true
181 }));
182 tr.addForm(new Form1099R({
183 payer: '401k',
184 payee: p,
185 grossDistribution: 27500,
186 taxableAmount: 0,
187 taxableAmountNotDetermined: false,
188 totalDistribution: false,
189 fedIncomeTax: 0,
190 employeeContributionsOrDesignatedRothContributions: 27500,
191 distributionCodes: [Box7Code.G],
192 iraSepSimple: false
193 }));
194 tr.addForm(new Form8606({
195 person: p,
196 nondeductibleContributions: 6000,
197 traditionalIraBasis: 0,
198 distributionFromTradSepOrSimpleIraOrMadeRothConversion: true,
199 contributionsMadeInCurrentYear: 0,
200 distributionsFromAllTradSepSimpleIras: 0,
201 valueOfAllTradSepSimpleIras: 0,
202 amountConvertedFromTradSepSimpleToRoth: 6000
203 }));
204 const f = new Form1040();
205 tr.addForm(f);
206
207 expect(f.getValue(tr, '4a')).toBe(6000);
208 expect(f.getValue(tr, '4b')).toBe(0);
209 });
210
211 test('itemized deductions', () => {
212 const tr = new TaxReturn();
213 const f = new Form1040({
214 filingStatus: FilingStatus.MarriedFilingJoint
215 });
216 tr.addForm(f);
217 tr.addForm(new ScheduleA({
218 charitableGiftsCashOrCheck: 26000
219 }));
220
221 expect(f.getValue(tr, '9')).toBe(26000);
222 });
223
224 test('itemized deductions, forced', () => {
225 const tr = new TaxReturn();
226 const f = new Form1040({
227 filingStatus: FilingStatus.MarriedFilingJoint
228 });
229 tr.addForm(f);
230 tr.addForm(new ScheduleA({
231 stateAndLocalIncomeAndSalesTaxes: 10000,
232 forceItemize: true
233 }));
234
235 expect(f.getValue(tr, '9')).toBe(10000);
236 });