file-card.spec.ts 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { ComponentFixture, TestBed } from '@angular/core/testing';
  2. import { provideMarkdown } from 'ngx-markdown';
  3. import { Message } from '../../../core/api/models';
  4. import { MessageBubbleComponent } from './message-bubble';
  5. /**
  6. * 文件 / 图片卡片(2026-10-30 重做)
  7. *
  8. * 锁住三件事:主区可点开、下载是独立按钮、两者互不触发。
  9. */
  10. describe('MessageBubble 文件卡片', () => {
  11. let fixture: ComponentFixture<MessageBubbleComponent>;
  12. function render(m: Message): void {
  13. fixture = TestBed.createComponent(MessageBubbleComponent);
  14. fixture.componentRef.setInput('message', m);
  15. fixture.componentRef.setInput('own', false);
  16. fixture.detectChanges();
  17. }
  18. beforeEach(async () => {
  19. await TestBed.configureTestingModule({
  20. imports: [MessageBubbleComponent],
  21. providers: [provideMarkdown()],
  22. }).compileComponents();
  23. });
  24. it('非图片文件渲染为卡片,含主区与下载按钮', () => {
  25. render({
  26. id: 'm1',
  27. conversationId: 'c',
  28. sender: 'agent',
  29. kind: 'text',
  30. ts: new Date().toISOString(),
  31. state: 'sent',
  32. file: {
  33. kind: 'file',
  34. name: '报告.html',
  35. size: 1024,
  36. mimeType: 'text/html',
  37. url: 'https://x/a.html',
  38. },
  39. });
  40. expect(fixture.nativeElement.querySelector('.file-card')).not.toBeNull();
  41. expect(fixture.nativeElement.querySelector('.file-main')).not.toBeNull();
  42. expect(fixture.nativeElement.querySelectorAll('.file-act').length).toBe(2);
  43. });
  44. it('点下载按钮只下载,不触发预览', () => {
  45. render({
  46. id: 'm1',
  47. conversationId: 'c',
  48. sender: 'agent',
  49. kind: 'text',
  50. ts: new Date().toISOString(),
  51. state: 'sent',
  52. file: { kind: 'file', name: 'a.html', size: 1, mimeType: 'text/html', url: 'https://x/a.html' },
  53. });
  54. const previews: unknown[] = [];
  55. fixture.componentInstance.preview.subscribe((f) => previews.push(f));
  56. const link: HTMLAnchorElement = fixture.nativeElement.querySelectorAll('.file-act')[1];
  57. /*
  58. * 🔴 必须先拦掉默认行为:<a download href> 在 Karma 里会真的发起导航,
  59. * 表现为 "Some of your tests did a full page reload!" 然后整个 runner 断连。
  60. */
  61. const stop = (e: Event) => e.preventDefault();
  62. link.addEventListener('click', stop);
  63. link.click();
  64. link.removeEventListener('click', stop);
  65. // 下载是 <a download>,不经过 preview 输出
  66. expect(previews.length).toBe(0);
  67. expect(link.getAttribute('download')).toBe('a.html');
  68. });
  69. it('点主区触发预览', () => {
  70. render({
  71. id: 'm1',
  72. conversationId: 'c',
  73. sender: 'agent',
  74. kind: 'text',
  75. ts: new Date().toISOString(),
  76. state: 'sent',
  77. file: { kind: 'file', name: 'a.png', size: 1, mimeType: 'image/png', url: 'https://x/a.png' },
  78. });
  79. let got = 0;
  80. fixture.componentInstance.preview.subscribe(() => got++);
  81. (fixture.nativeElement.querySelector('button[aria-label="预览图片 a.png"]') as HTMLElement).click();
  82. expect(got).toBe(1);
  83. });
  84. });