Include exempt interest dividends in 1040-2a.
[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, { GainType } from './Form1099B';
13 import Form1099R, { Box7Code } from './Form1099R';
14 import Schedule2 from './Schedule2';
15 import ScheduleD, { ScheduleDTaxWorksheet } from './ScheduleD';
16 import Form8606 from './Form8606';
17 import Form8959 from './Form8959';
18 import Form8949 from './Form8949';
19 import TaxReturn from './TaxReturn';
20 import W2 from './W2';
21
22 test('w2 wages', () => {
23 const pa = Person.self('A');
24 const pb = Person.spouse('B');
25 const tr = new TaxReturn();
26 tr.addPerson(pa);
27 tr.addPerson(pb);
28 tr.addForm(new W2({
29 employer: 'AA',
30 employee: pa,
31 wages: 130000.00,
32 fedIncomeTax: 0,
33 medicareWages: 0,
34 }));
35 tr.addForm(new W2({
36 employer: 'BB',
37 employee: pb,
38 wages: 36.32,
39 fedIncomeTax: 0,
40 medicareWages: 0,
41 }));
42 const f1040 = new Form1040({ filingStatus: FilingStatus.MarriedFilingJoint });
43 tr.addForm(f1040);
44 tr.addForm(new Schedule2);
45 expect(f1040.getValue(tr, '1')).toBe(130036.32);
46 f1040.getValue(tr, '23');
47 });
48
49 test('interest income', () => {
50 const p = Person.self('A');
51 const tr = new TaxReturn();
52 tr.addPerson(p);
53 tr.addForm(new Form1099INT({
54 payer: 'Bank',
55 payee: p,
56 interest: 100,
57 taxExemptInterest: 0
58 }));
59 tr.addForm(new Form1099INT({
60 payer: 'Bank 2',
61 payee: p,
62 interest: 3.50,
63 taxExemptInterest: 95
64 }));
65
66 const f1040 = new Form1040();
67 tr.addForm(f1040);
68
69 expect(f1040.getValue(tr, '2a')).toBe(95);
70 expect(f1040.getValue(tr, '2b')).toBe(103.5);
71 });
72
73 test('dividend income', () => {
74 const p = Person.self('A');
75 const tr = new TaxReturn();
76 tr.addPerson(p);
77 const f1099div = new Form1099DIV({
78 payer: 'Brokerage',
79 payee: p,
80 ordinaryDividends: 100,
81 qualifiedDividends: 75,
82 totalCapitalGain: 100
83 });
84 tr.addForm(f1099div);
85 tr.addForm(f1099div);
86
87 const f1040 = new Form1040();
88 tr.addForm(f1040);
89
90 expect(f1040.getValue(tr, '3a')).toBe(75 * 2);
91 expect(f1040.getValue(tr, '3b')).toBe(200);
92 });
93
94 test('tax-exempt interest', () => {
95 const p = Person.self('A');
96 const tr = new TaxReturn();
97 tr.addPerson(p);
98 tr.addForm(new Form1099DIV({
99 payer: 'Brokerage',
100 payee: p,
101 exemptInterestDividends: 100,
102 }));
103 tr.addForm(new Form1099INT({
104 payer: 'Bank',
105 payee: p,
106 interest: 0,
107 taxExemptInterest: 50
108 }));
109
110 const f1040 = new Form1040();
111 tr.addForm(f1040);
112
113 expect(f1040.getValue(tr, '2a')).toBe(150);
114 });
115
116 test('capital gain/loss', () => {
117 const p = Person.self('A');
118 const tr = new TaxReturn();
119 tr.addPerson(p);
120 tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
121 tr.addForm(new W2({
122 employer: 'Money',
123 employee: p,
124 wages: 150000
125 }));
126 tr.addForm(new Form1099B({
127 payer: 'Brokerage',
128 payee: p,
129 description: '10 FNDC',
130 proceeds: 1000,
131 costBasis: 800,
132 gainType: GainType.LongTerm,
133 basisReportedToIRS: true
134 }));
135 tr.addForm(new Form8949);
136 tr.addForm(new ScheduleD());
137 tr.addForm(new ScheduleDTaxWorksheet());
138 tr.getForm(ScheduleD).getValue(tr, '21');
139 tr.getForm(Form1040).getValue(tr, '12a');
140 });
141
142 test('require Form8959', () => {
143 const p = Person.self('A');
144 const tr = new TaxReturn();
145 tr.addPerson(p);
146 tr.addForm(new W2({
147 employer: 'Company',
148 employee: p,
149 wages: 400000,
150 }));
151 const f1040 = new Form1040({
152 filingStatus: FilingStatus.MarriedFilingSeparate,
153 });
154 tr.addForm(f1040);
155 tr.addForm(new Schedule2);
156
157 expect(() => f1040.getValue(tr, '15')).toThrow(NotFoundError);
158 expect(() => f1040.getValue(tr, '15')).toThrow('Form8959');
159 expect(f1040.getValue(tr, '1')).toBe(400000);
160 expect(f1040.getValue(tr, '8b')).toBe(400000);
161 });
162
163 test('backdoor and megabackdoor roth', () => {
164 const p = Person.self('A');
165 const tr = new TaxReturn();
166 tr.addPerson(p);
167 tr.addForm(new Form1099R({
168 payer: 'Roth',
169 payee: p,
170 grossDistribution: 6000,
171 taxableAmount: 6000,
172 taxableAmountNotDetermined: true,
173 totalDistribution: true,
174 fedIncomeTax: 0,
175 distributionCodes: [Box7Code._2],
176 iraSepSimple: true
177 }));
178 tr.addForm(new Form1099R({
179 payer: '401k',
180 payee: p,
181 grossDistribution: 27500,
182 taxableAmount: 0,
183 taxableAmountNotDetermined: false,
184 totalDistribution: false,
185 fedIncomeTax: 0,
186 employeeContributionsOrDesignatedRothContributions: 27500,
187 distributionCodes: [Box7Code.G],
188 iraSepSimple: false
189 }));
190 tr.addForm(new Form8606({
191 person: p,
192 nondeductibleContributions: 6000,
193 traditionalIraBasis: 0,
194 distributionFromTradSepOrSimpleIraOrMadeRothConversion: true,
195 contributionsMadeInCurrentYear: 0,
196 distributionsFromAllTradSepSimpleIras: 0,
197 valueOfAllTradSepSimpleIras: 0,
198 amountConvertedFromTradSepSimpleToRoth: 6000
199 }));
200 const f = new Form1040();
201 tr.addForm(f);
202
203 expect(f.getValue(tr, '4a')).toBe(6000);
204 expect(f.getValue(tr, '4b')).toBe(0);
205 });