import { newSpecPage } from '@stencil/core/testing';
import { BcxMessageComposer } from '../bcx-message-composer';
describe('bcx-message-composer', () => {
it('renders with default props', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
expect(page.root).toEqualHtml(`
`);
});
it('renders with custom props', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const textarea = page.root.shadowRoot.querySelector('textarea');
const button = page.root.shadowRoot.querySelector('button[type="submit"]');
expect(textarea.getAttribute('placeholder')).toBe('Custom placeholder');
expect(textarea.getAttribute('maxlength')).toBe('500');
expect(button.hasAttribute('disabled')).toBe(true);
});
it('enables submit button when message is entered', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const button = page.root.shadowRoot.querySelector('button[type="submit"]');
// Initially disabled
expect(button.hasAttribute('disabled')).toBe(true);
// Enter message
component.message = 'Hello world';
await page.waitForChanges();
expect(button.hasAttribute('disabled')).toBe(false);
});
it('emits messageSubmit event on form submit', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const form = page.root.shadowRoot.querySelector('form');
// Set up event listener
const messageSubmitSpy = jest.fn();
page.root.addEventListener('messageSubmit', messageSubmitSpy);
// Enter message and submit
component.message = 'Test message';
await page.waitForChanges();
form.dispatchEvent(new Event('submit'));
await page.waitForChanges();
expect(messageSubmitSpy).toHaveBeenCalledWith(
expect.objectContaining({
detail: { content: 'Test message', images: [] },
}),
);
});
it('handles Enter key submission', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const textarea = page.root.shadowRoot.querySelector('textarea');
// Set up event listener
const messageSubmitSpy = jest.fn();
page.root.addEventListener('messageSubmit', messageSubmitSpy);
// Enter message
component.message = 'Test message';
await page.waitForChanges();
// Simulate Enter key
const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
textarea.dispatchEvent(enterEvent);
await page.waitForChanges();
expect(messageSubmitSpy).toHaveBeenCalledWith(
expect.objectContaining({
detail: { content: 'Test message', images: [] },
}),
);
});
it('does not submit on Shift+Enter', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const textarea = page.root.shadowRoot.querySelector('textarea');
// Set up event listener
const messageSubmitSpy = jest.fn();
page.root.addEventListener('messageSubmit', messageSubmitSpy);
// Enter message
component.message = 'Test message';
await page.waitForChanges();
// Simulate Shift+Enter key
const shiftEnterEvent = new KeyboardEvent('keydown', { key: 'Enter', shiftKey: true });
textarea.dispatchEvent(shiftEnterEvent);
await page.waitForChanges();
expect(messageSubmitSpy).not.toHaveBeenCalled();
});
it('emits attachmentsChange with count 0 when clearAttachments is called', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const attachmentsSpy = jest.fn();
page.root.addEventListener('attachmentsChange', attachmentsSpy);
await component.clearAttachments();
await page.waitForChanges();
expect(attachmentsSpy).toHaveBeenCalledWith(expect.objectContaining({ detail: { count: 0 } }));
});
it('emits attachmentsChange with count 0 after message submit clears previews', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const form = page.root.shadowRoot.querySelector('form');
const attachmentsSpy = jest.fn();
page.root.addEventListener('attachmentsChange', attachmentsSpy);
component.message = 'Hello';
await page.waitForChanges();
form.dispatchEvent(new Event('submit'));
await page.waitForChanges();
expect(attachmentsSpy).toHaveBeenCalledWith(expect.objectContaining({ detail: { count: 0 } }));
});
it('keeps submit disabled when only images are attached', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const button = page.root.shadowRoot.querySelector('button[type="submit"]');
(component as any).images = [{ id: 'img-1', file: new File(['x'], 'img.png', { type: 'image/png' }), dataUrl: 'data:image/png;base64,xxx' }];
await page.waitForChanges();
expect(button.hasAttribute('disabled')).toBe(true);
});
it('does not emit messageSubmit when only images are attached and submit is triggered', async () => {
const page = await newSpecPage({
components: [BcxMessageComposer],
html: '',
});
const component = page.rootInstance as BcxMessageComposer;
const form = page.root.shadowRoot.querySelector('form');
const messageSubmitSpy = jest.fn();
page.root.addEventListener('messageSubmit', messageSubmitSpy);
(component as any).images = [{ id: 'img-1', file: new File(['x'], 'img.png', { type: 'image/png' }), dataUrl: 'data:image/png;base64,xxx' }];
await page.waitForChanges();
form.dispatchEvent(new Event('submit'));
await page.waitForChanges();
expect(messageSubmitSpy).not.toHaveBeenCalled();
});
});