import { describe, it, expect, beforeEach } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; import { Decimal } from 'decimal.js'; import SettleShareModal from '../SettleShareModal.vue'; // Adjust path as needed import type { ExpenseSplitInfo } from '../SettleShareModal.vue'; // Import the interface // Default props generator const getDefaultProps = (overrides: Record = {}) => ({ show: true, split: { id: 1, user_id: 100, owed_amount: '50.00', user: { id: 100, name: 'Test User', email: 'user@example.com' }, } as ExpenseSplitInfo, paidAmount: 10.00, isLoading: false, ...overrides, }); describe('SettleShareModal.vue', () => { let wrapper: VueWrapper; const mountComponent = (props: Record) => { wrapper = mount(SettleShareModal, { props: getDefaultProps(props), }); }; beforeEach(() => { // Default mount before each test, can be overridden in specific tests mountComponent({}); }); it('renders when show is true', () => { expect(wrapper.find('.modal-backdrop-settle').exists()).toBe(true); }); it('does not render when show is false', () => { mountComponent({ show: false }); expect(wrapper.find('.modal-backdrop-settle').exists()).toBe(false); }); it('displays correct split information', () => { const props = getDefaultProps({ split: { id: 2, user_id: 101, owed_amount: '75.50', user: { id: 101, name: 'Jane Doe', email: 'jane@example.com' }, }, paidAmount: 25.00, }); mountComponent(props); const html = wrapper.html(); expect(html).toContain('Jane Doe'); expect(html).toContain('$75.50'); // Owed amount expect(html).toContain('$25.00'); // Paid amount const expectedRemaining = new Decimal(props.split.owed_amount).minus(new Decimal(props.paidAmount)).toFixed(2); expect(html).toContain(`$${expectedRemaining}`); // Remaining amount }); it('calculates and displays correct remaining amount', () => { const owed = '100.00'; const paid = 30.00; const remaining = new Decimal(owed).minus(paid).toFixed(2); mountComponent({ split: { ...getDefaultProps().split, owed_amount: owed }, paidAmount: paid }); const remainingAmountStrong = wrapper.find('.amount-to-settle'); expect(remainingAmountStrong.exists()).toBe(true); expect(remainingAmountStrong.text()).toBe(`$${remaining}`); }); it('emits "confirm" with correct amount when Confirm Payment is clicked', async () => { const owed = '50.00'; const paid = 10.00; const expectedSettleAmount = new Decimal(owed).minus(paid).toNumber(); mountComponent({ split: { ...getDefaultProps().split, owed_amount: owed }, paidAmount: paid }); await wrapper.find('.btn-primary-settle').trigger('click'); expect(wrapper.emitted().confirm).toBeTruthy(); expect(wrapper.emitted().confirm[0]).toEqual([expectedSettleAmount]); }); it('emits "cancel" when Cancel button is clicked', async () => { await wrapper.find('.btn-neutral-settle').trigger('click'); expect(wrapper.emitted().cancel).toBeTruthy(); }); it('emits "cancel" when backdrop is clicked', async () => { await wrapper.find('.modal-backdrop-settle').trigger('click.self'); expect(wrapper.emitted().cancel).toBeTruthy(); }); it('disables Confirm Payment button when isLoading is true', () => { mountComponent({ isLoading: true }); const confirmButton = wrapper.find('.btn-primary-settle'); expect((confirmButton.element as HTMLButtonElement).disabled).toBe(true); }); it('disables Confirm Payment button when remaining amount is zero or less', () => { mountComponent({ split: { ...getDefaultProps().split, owed_amount: '20.00' }, paidAmount: 20.00 }); // remaining is 0 const confirmButton = wrapper.find('.btn-primary-settle'); expect((confirmButton.element as HTMLButtonElement).disabled).toBe(true); mountComponent({ split: { ...getDefaultProps().split, owed_amount: '19.00' }, paidAmount: 20.00 }); // remaining is < 0 (overpaid) const confirmButtonNegative = wrapper.find('.btn-primary-settle'); expect((confirmButtonNegative.element as HTMLButtonElement).disabled).toBe(true); }); it('Confirm Payment button is enabled when there is a positive remaining amount and not loading', () => { mountComponent({ split: { ...getDefaultProps().split, owed_amount: '20.00' }, paidAmount: 10.00, isLoading: false }); const confirmButton = wrapper.find('.btn-primary-settle'); expect((confirmButton.element as HTMLButtonElement).disabled).toBe(false); }); });