operations-store-detail.component.spec.ts 4.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { ComponentFixture, TestBed } from '@angular/core/testing';
  2. import { ActivatedRoute, convertToParamMap, provideRouter } from '@angular/router';
  3. import { StoreDetailData } from '../admin.models';
  4. import { OperationsService } from '../operations.service';
  5. import { OperationsStoreDetailComponent } from './operations-store-detail.component';
  6. function storeDetail(month: string): StoreDetailData {
  7. return {
  8. store: {
  9. objectId: 'store-1', userId: 2, username: 'store', storeName: '南昌总店', contactName: '负责人', mobile: '', mobileMasked: '138****0000',
  10. parentStoreId: 0, parentStoreName: '', memberCount: 1, coachCount: 1, todayAppointments: 0, totalAppointments: 1, lastAppointmentAt: '',
  11. registeredAt: '2024-01-01T00:00:00.000Z', lastLoginAt: '', loginCount: 0, status: 'active', statusLabel: '正常', updatedAt: '',
  12. },
  13. month,
  14. summary: { memberCount: 1, coachCount: 1, monthAppointments: 1, completedAppointments: 0, activeStudents: 1, lessonCount: 1, totalHours: 1, estimatedCoachPay: 40 },
  15. members: [{ objectId: 'member-1', userId: 100, displayName: '测试学员', username: 'student', mobile: '', mobileMasked: '139****0000', groupId: 1, groupName: '会员', parentUserId: 2, parentDisplayName: '南昌总店', periods30: 1, periods60: 1, trialPeriods: 0, activeCourseCount: 1, completedCourseCount: 0, studyRecordCount: 0, appointmentCount: 1, learningStatus: 'studying', learningStatusLabel: '学习中', learningStatusReason: '有排课', registeredAt: '', lastLoginAt: '', loginCount: 0, status: 'active', statusLabel: '正常', canRevealMobile: false, updatedAt: '' }],
  16. coaches: [{ objectId: 'coach-1', userId: 200, username: 'coach', displayName: '测试陪练', mobile: '', mobileMasked: '137****0000', parentUserId: 2, storeName: '南昌总店', status: 'active', statusLabel: '正常', todayAppointments: 0, pendingAppointments: 1, totalAppointments: 1, lastAppointmentAt: '', monthLessons: 1, monthHours: 1, estimatedPay: 40, averageScore: 5, lastLessonAt: '', availabilityConfigured: false, updatedAt: '' }],
  17. appointments: [{ targetId: 'appointment-1', generalId: 1, studentObjectId: 'member-1', studentId: 100, studentName: '测试学员', coachObjectId: 'coach-1', coachId: 200, coachName: '测试陪练', courseId: 300, courseName: '测试课程', classType: 2, classTypeLabel: '60 分钟', deliveryMethod: '线上', startsAt: `${month}-10T02:00:00.000Z`, endsAt: `${month}-10T03:00:00.000Z`, statusCode: 0, statusLabel: '待开始', cancelled: false, cancellationReason: '', coachAccountMissing: false, availabilityWarning: false, source: 'parse', sourceLabel: '新系统', readOnly: false, updatedAt: '' }],
  18. courses: [{ courseId: 300, courseName: '测试课程', appointmentCount: 1, completedCount: 0, studentCount: 1, completionRate: 0, lastAppointmentAt: `${month}-10T02:00:00.000Z` }],
  19. commissionStatus: { available: false, message: '旧系统没有可验证的门店佣金规则' },
  20. payrollSourceStatus: { mode: 'live', available: true, message: '', total: 1, refreshedAt: '' },
  21. refreshedAt: '',
  22. };
  23. }
  24. describe('OperationsStoreDetailComponent', () => {
  25. let fixture: ComponentFixture<OperationsStoreDetailComponent>;
  26. let operations: jasmine.SpyObj<OperationsService>;
  27. beforeEach(async () => {
  28. operations = jasmine.createSpyObj<OperationsService>('OperationsService', ['storeDetail']);
  29. operations.storeDetail.and.callFake((_objectId, month) => Promise.resolve(storeDetail(month)));
  30. await TestBed.configureTestingModule({
  31. imports: [OperationsStoreDetailComponent],
  32. providers: [
  33. provideRouter([]),
  34. { provide: OperationsService, useValue: operations },
  35. { provide: ActivatedRoute, useValue: { snapshot: { paramMap: convertToParamMap({ objectId: 'store-1' }) } } },
  36. ],
  37. }).compileComponents();
  38. fixture = TestBed.createComponent(OperationsStoreDetailComponent);
  39. fixture.detectChanges();
  40. await fixture.whenStable();
  41. fixture.detectChanges();
  42. });
  43. it('loads store operations and changes its reporting month', async () => {
  44. const component = fixture.componentInstance;
  45. expect(component.data()?.store.storeName).toBe('南昌总店');
  46. component.changeMonth('2026-08');
  47. await fixture.whenStable();
  48. expect(operations.storeDetail).toHaveBeenCalledWith('store-1', '2026-08', false);
  49. expect(component.data()?.month).toBe('2026-08');
  50. });
  51. it('keeps members, coaches, schedule and course fulfillment as business tabs', () => {
  52. const element: HTMLElement = fixture.nativeElement;
  53. expect(element.textContent).toContain('归属会员');
  54. expect(element.textContent).toContain('归属陪练');
  55. expect(element.textContent).toContain('课程履约');
  56. expect(element.textContent).toContain('门店佣金暂不估算');
  57. expect(fixture.componentInstance.statusTone(storeDetail('2026-09').appointments[0])).toBe('pending');
  58. });
  59. });