/** * ContactListItem Component Tests * * Comprehensive test suite for the ContactListItem component. * Tests component rendering, props, events, and user interactions. * * @author Matthew Raymer */ import { describe, it, expect, beforeEach } from "vitest"; import { mount } from "@vue/test-utils"; import ContactListItem from "@/components/ContactListItem.vue"; import { createStandardMockContact } from "@/test/factories/contactFactory"; import { createComponentWrapper, testLifecycleEvents, testPerformance, testAccessibility, testErrorHandling, } from "@/test/utils/componentTestUtils"; describe("ContactListItem", () => { let wrapper: any; beforeEach(() => { wrapper = null; }); const mountComponent = (props = {}) => { return mount(ContactListItem, { props: { contact: createStandardMockContact(), activeDid: "did:ethr:test:active", showCheckbox: false, showActions: false, isSelected: false, showGiveTotals: true, showGiveConfirmed: true, givenToMeDescriptions: {}, givenToMeConfirmed: {}, givenToMeUnconfirmed: {}, givenByMeDescriptions: {}, givenByMeConfirmed: {}, givenByMeUnconfirmed: {}, ...props, }, global: { stubs: { EntityIcon: { template: '
', props: ["contact", "iconSize"], }, "font-awesome": { template: 'FontAwesome', }, }, }, }); }; describe("Component Rendering", () => { it("should render with correct structure when all props are provided", () => { wrapper = mountComponent(); expect(wrapper.exists()).toBe(true); expect(wrapper.find('[data-testid="contactListItem"]').exists()).toBe( true, ); expect(wrapper.find(".entity-icon-stub").exists()).toBe(true); expect(wrapper.find("h2").exists()).toBe(true); }); it("should display contact name correctly", () => { const contact = createStandardMockContact({ name: "Test Contact" }); wrapper = mountComponent({ contact }); expect( wrapper .find("h2") .text() .replace(/\u00A0/g, " "), ).toContain("Test Contact"); }); it("should display contact DID correctly", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact }); expect(wrapper.text()).toContain("did:ethr:test:123"); }); it("should display contact notes when available", () => { const contact = createStandardMockContact({ notes: "Test notes" }); wrapper = mountComponent({ contact }); expect(wrapper.text()).toContain("Test notes"); }); }); describe("Checkbox Functionality", () => { it("should show checkbox when showCheckbox is true", () => { wrapper = mountComponent({ showCheckbox: true }); expect(wrapper.find('[data-testid="contactCheckOne"]').exists()).toBe( true, ); }); it("should not show checkbox when showCheckbox is false", () => { wrapper = mountComponent({ showCheckbox: false }); expect(wrapper.find('[data-testid="contactCheckOne"]').exists()).toBe( false, ); }); it("should emit toggle-selection event when checkbox is clicked", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ showCheckbox: true, contact }); wrapper.find('[data-testid="contactCheckOne"]').trigger("click"); expect(wrapper.emitted("toggle-selection")).toBeTruthy(); expect(wrapper.emitted("toggle-selection")[0]).toEqual([ "did:ethr:test:123", ]); }); it("should reflect isSelected prop in checkbox state", () => { wrapper = mountComponent({ showCheckbox: true, isSelected: true }); const checkbox = wrapper.find('[data-testid="contactCheckOne"]'); expect(checkbox.attributes("checked")).toBeDefined(); }); }); describe("Actions Section", () => { it("should show actions when showActions is true and contact is not active", () => { wrapper = mountComponent({ showActions: true, contact: createStandardMockContact({ did: "did:ethr:test:other" }), }); expect(wrapper.find('[data-testid="offerButton"]').exists()).toBe(true); }); it("should not show actions when contact is active", () => { const contact = createStandardMockContact({ did: "did:ethr:test:active", }); wrapper = mountComponent({ showActions: true, contact, activeDid: "did:ethr:test:active", }); expect(wrapper.find('[data-testid="offerButton"]').exists()).toBe(false); }); it("should emit show-identicon event when EntityIcon is clicked", () => { const contact = createStandardMockContact(); wrapper = mountComponent({ contact }); wrapper.find(".entity-icon-stub").trigger("click"); expect(wrapper.emitted("show-identicon")).toBeTruthy(); expect(wrapper.emitted("show-identicon")[0]).toEqual([contact]); }); it("should emit open-offer-dialog event when offer button is clicked", () => { wrapper = mountComponent({ showActions: true, contact: createStandardMockContact({ did: "did:ethr:test:other" }), }); wrapper.find('[data-testid="offerButton"]').trigger("click"); expect(wrapper.emitted("open-offer-dialog")).toBeTruthy(); expect(wrapper.emitted("open-offer-dialog")[0][0]).toBe( "did:ethr:test:other", ); }); }); describe("Give Amounts Display", () => { it("should display give amounts correctly for given to me", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact, showActions: true, givenToMeConfirmed: { "did:ethr:test:123": 50 }, givenToMeUnconfirmed: { "did:ethr:test:123": 25 }, }); const buttons = wrapper.findAll("button"); if (buttons.length > 0) { expect(buttons[0].text()).toBe("75"); // 50 + 25 } }); it("should display give amounts correctly for given by me", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact, showActions: true, givenByMeConfirmed: { "did:ethr:test:123": 30 }, givenByMeUnconfirmed: { "did:ethr:test:123": 20 }, }); const buttons = wrapper.findAll("button"); if (buttons.length > 1) { expect(buttons[1].text()).toBe("50"); // 30 + 20 } }); it("should show only confirmed amounts when showGiveConfirmed is true", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact, showActions: true, showGiveTotals: false, showGiveConfirmed: true, givenToMeConfirmed: { "did:ethr:test:123": 50 }, givenToMeUnconfirmed: { "did:ethr:test:123": 25 }, }); const buttons = wrapper.findAll("button"); if (buttons.length > 0) { expect(buttons[0].text()).toBe("50"); // Only confirmed } }); it("should show only unconfirmed amounts when showGiveConfirmed is false", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact, showActions: true, showGiveTotals: false, showGiveConfirmed: false, givenToMeConfirmed: { "did:ethr:test:123": 50 }, givenToMeUnconfirmed: { "did:ethr:test:123": 25 }, }); const buttons = wrapper.findAll("button"); if (buttons.length > 0) { expect(buttons[0].text()).toBe("25"); // Only unconfirmed } }); }); describe("Error Handling", () => { it("should handle undefined contact name gracefully", () => { const contact = createStandardMockContact({ name: undefined }); wrapper = mountComponent({ contact }); expect( wrapper .find("h2") .text() .replace(/\u00A0/g, " "), ).toContain("(no name)"); }); it("should handle missing give amounts gracefully", () => { const contact = createStandardMockContact({ did: "did:ethr:test:123" }); wrapper = mountComponent({ contact, showActions: true, givenToMeConfirmed: {}, givenToMeUnconfirmed: {}, givenByMeConfirmed: {}, givenByMeUnconfirmed: {}, }); const buttons = wrapper.findAll("button"); if (buttons.length > 0) { expect(buttons[0].text()).toBe("0"); } if (buttons.length > 1) { expect(buttons[1].text()).toBe("0"); } }); it("should handle rapid prop changes gracefully", () => { wrapper = mountComponent(); for (let i = 0; i < 10; i++) { wrapper.setProps({ isSelected: i % 2 === 0, showCheckbox: i % 3 === 0, showActions: i % 4 === 0, }); } expect(wrapper.exists()).toBe(true); }); }); describe("Performance Testing", () => { it("should render within performance threshold", () => { const performanceResult = testPerformance(() => { mountComponent(); }, 50); expect(performanceResult.passed).toBe(true); expect(performanceResult.duration).toBeLessThan(50); }); it("should handle multiple re-renders efficiently", () => { wrapper = mountComponent(); const start = performance.now(); for (let i = 0; i < 50; i++) { wrapper.setProps({ isSelected: i % 2 === 0 }); } const end = performance.now(); expect(end - start).toBeLessThan(200); }); it("should establish performance baseline", () => { const start = performance.now(); wrapper = mountComponent(); const end = performance.now(); console.log("Performance Baseline:", { renderTime: end - start, }); expect(end - start).toBeLessThan(100); }); }); describe("Integration Testing", () => { it("should integrate with EntityIcon component correctly", () => { const contact = createStandardMockContact(); wrapper = mountComponent({ contact }); const entityIcon = wrapper.find(".entity-icon-stub"); expect(entityIcon.exists()).toBe(true); }); it("should handle multiple concurrent events", () => { wrapper = mountComponent({ showCheckbox: true, showActions: true }); // Simulate multiple rapid interactions wrapper.find('[data-testid="contactCheckOne"]').trigger("click"); wrapper.find(".entity-icon-stub").trigger("click"); wrapper.find('[data-testid="offerButton"]').trigger("click"); expect(wrapper.emitted("toggle-selection")).toBeTruthy(); expect(wrapper.emitted("show-identicon")).toBeTruthy(); expect(wrapper.emitted("open-offer-dialog")).toBeTruthy(); }); }); describe("Snapshot Testing", () => { it("should maintain consistent DOM structure", () => { wrapper = mountComponent(); const html = wrapper.html(); expect(html).toMatch(/