|
1 | 1 | import { Store } from '@ngxs/store'; |
2 | 2 |
|
3 | | -import { MockComponent, MockProvider } from 'ng-mocks'; |
4 | | - |
5 | | -import { of } from 'rxjs'; |
| 3 | +import { MockComponent } from 'ng-mocks'; |
6 | 4 |
|
7 | 5 | import { ComponentFixture, TestBed } from '@angular/core/testing'; |
8 | | -import { ActivatedRoute, Router } from '@angular/router'; |
9 | 6 |
|
10 | | -import { DraftRegistrationAttributesJsonApi } from '@osf/shared/models/registration/registration-json-api.model'; |
| 7 | +import { RegistriesSelectors, UpdateDraft } from '@osf/features/registries/store'; |
| 8 | +import { DraftRegistrationModel } from '@osf/shared/models/registration/draft-registration.model'; |
11 | 9 |
|
12 | 10 | import { CustomStepComponent } from '../../components/custom-step/custom-step.component'; |
13 | | -import { RegistriesSelectors, UpdateDraft } from '../../store'; |
14 | 11 |
|
15 | 12 | import { DraftRegistrationCustomStepComponent } from './draft-registration-custom-step.component'; |
16 | 13 |
|
17 | | -import { OSFTestingModule } from '@testing/osf.testing.module'; |
18 | | -import { ActivatedRouteMockBuilder } from '@testing/providers/route-provider.mock'; |
19 | | -import { RouterMockBuilder } from '@testing/providers/router-provider.mock'; |
| 14 | +import { MOCK_REGISTRIES_PAGE } from '@testing/mocks/registries.mock'; |
| 15 | +import { provideOSFCore } from '@testing/osf.testing.provider'; |
| 16 | +import { ActivatedRouteMockBuilder, provideActivatedRouteMock } from '@testing/providers/route-provider.mock'; |
| 17 | +import { provideRouterMock, RouterMockBuilder, RouterMockType } from '@testing/providers/router-provider.mock'; |
20 | 18 | import { provideMockStore } from '@testing/providers/store-provider.mock'; |
21 | 19 |
|
| 20 | +const MOCK_DRAFT: Partial<DraftRegistrationModel> = { |
| 21 | + id: 'draft-1', |
| 22 | + providerId: 'prov-1', |
| 23 | + branchedFrom: { id: 'node-1', filesLink: '/files' }, |
| 24 | +}; |
| 25 | +const MOCK_STEPS_DATA: Record<string, string> = { 'question-1': 'answer-1' }; |
| 26 | + |
22 | 27 | describe('DraftRegistrationCustomStepComponent', () => { |
23 | 28 | let component: DraftRegistrationCustomStepComponent; |
24 | 29 | let fixture: ComponentFixture<DraftRegistrationCustomStepComponent>; |
25 | 30 | let store: Store; |
26 | | - let mockRouter: ReturnType<RouterMockBuilder['build']>; |
27 | | - let mockActivatedRoute: ReturnType<ActivatedRouteMockBuilder['build']>; |
28 | | - |
29 | | - const mockStepsData = { stepKey: { field: 'value' } }; |
30 | | - const mockDraftRegistration = { |
31 | | - id: 'draft-1', |
32 | | - providerId: 'prov-1', |
33 | | - branchedFrom: { id: 'proj-1', filesLink: '/project/proj-1/files/' }, |
34 | | - }; |
35 | | - |
36 | | - beforeEach(async () => { |
37 | | - mockRouter = RouterMockBuilder.create().build(); |
38 | | - mockActivatedRoute = ActivatedRouteMockBuilder.create().withParams({ id: 'draft-1' }).build(); |
39 | | - |
40 | | - await TestBed.configureTestingModule({ |
41 | | - imports: [DraftRegistrationCustomStepComponent, OSFTestingModule, MockComponent(CustomStepComponent)], |
| 31 | + let mockRouter: RouterMockType; |
| 32 | + |
| 33 | + function setup( |
| 34 | + draft: Partial<DraftRegistrationModel> | null = MOCK_DRAFT, |
| 35 | + stepsData: Record<string, string> = MOCK_STEPS_DATA |
| 36 | + ) { |
| 37 | + const mockRoute = ActivatedRouteMockBuilder.create().withParams({ id: 'draft-1', step: '1' }).build(); |
| 38 | + mockRouter = RouterMockBuilder.create().withUrl('/registries/prov-1/draft/draft-1/custom').build(); |
| 39 | + |
| 40 | + TestBed.configureTestingModule({ |
| 41 | + imports: [DraftRegistrationCustomStepComponent, MockComponent(CustomStepComponent)], |
42 | 42 | providers: [ |
43 | | - MockProvider(Router, mockRouter), |
44 | | - MockProvider(ActivatedRoute, mockActivatedRoute), |
| 43 | + provideOSFCore(), |
| 44 | + provideActivatedRouteMock(mockRoute), |
| 45 | + provideRouterMock(mockRouter), |
45 | 46 | provideMockStore({ |
46 | 47 | signals: [ |
47 | | - { selector: RegistriesSelectors.getStepsData, value: mockStepsData }, |
48 | | - { selector: RegistriesSelectors.getDraftRegistration, value: mockDraftRegistration }, |
| 48 | + { selector: RegistriesSelectors.getStepsData, value: stepsData }, |
| 49 | + { selector: RegistriesSelectors.getDraftRegistration, value: draft }, |
| 50 | + { selector: RegistriesSelectors.getPagesSchema, value: [MOCK_REGISTRIES_PAGE] }, |
| 51 | + { selector: RegistriesSelectors.getStepsState, value: { 1: { invalid: false } } }, |
49 | 52 | ], |
50 | 53 | }), |
51 | 54 | ], |
52 | | - }).compileComponents(); |
| 55 | + }); |
53 | 56 |
|
54 | 57 | fixture = TestBed.createComponent(DraftRegistrationCustomStepComponent); |
55 | 58 | component = fixture.componentInstance; |
56 | 59 | store = TestBed.inject(Store); |
57 | | - (store.dispatch as jest.Mock).mockReturnValue(of(void 0)); |
58 | 60 | fixture.detectChanges(); |
59 | | - }); |
| 61 | + } |
60 | 62 |
|
61 | 63 | it('should create', () => { |
| 64 | + setup(); |
62 | 65 | expect(component).toBeTruthy(); |
63 | 66 | }); |
64 | 67 |
|
65 | | - it('should return stepsData and draftRegistration from store', () => { |
66 | | - expect(component.stepsData()).toEqual(mockStepsData); |
67 | | - expect(component.draftRegistration()).toEqual(mockDraftRegistration); |
68 | | - }); |
69 | | - |
70 | | - it('should compute filesLink from draftRegistration branchedFrom', () => { |
71 | | - expect(component.filesLink()).toBe('/project/proj-1/files/'); |
72 | | - }); |
73 | | - |
74 | | - it('should compute provider from draftRegistration providerId', () => { |
| 68 | + it('should compute inputs from draft registration', () => { |
| 69 | + setup(); |
| 70 | + expect(component.filesLink()).toBe('/files'); |
75 | 71 | expect(component.provider()).toBe('prov-1'); |
| 72 | + expect(component.projectId()).toBe('node-1'); |
76 | 73 | }); |
77 | 74 |
|
78 | | - it('should compute projectId from draftRegistration branchedFrom id', () => { |
79 | | - expect(component.projectId()).toBe('proj-1'); |
| 75 | + it('should return empty strings when draftRegistration is null', () => { |
| 76 | + setup(null, {}); |
| 77 | + expect(component.filesLink()).toBe(''); |
| 78 | + expect(component.provider()).toBe(''); |
| 79 | + expect(component.projectId()).toBe(''); |
80 | 80 | }); |
81 | 81 |
|
82 | | - it('should dispatch UpdateDraft with id and registration_responses payload on onUpdateAction', () => { |
83 | | - const attributes: Partial<DraftRegistrationAttributesJsonApi> = { |
84 | | - registration_responses: { field1: 'value1' }, |
85 | | - }; |
86 | | - (store.dispatch as jest.Mock).mockClear(); |
87 | | - |
88 | | - component.onUpdateAction(attributes); |
89 | | - |
90 | | - expect(store.dispatch).toHaveBeenCalledWith(expect.any(UpdateDraft)); |
91 | | - const call = (store.dispatch as jest.Mock).mock.calls.find((c) => c[0] instanceof UpdateDraft); |
92 | | - expect(call[0].draftId).toBe('draft-1'); |
93 | | - expect(call[0].attributes).toEqual({ registration_responses: { registration_responses: { field1: 'value1' } } }); |
| 82 | + it('should dispatch updateDraft with wrapped registration_responses', () => { |
| 83 | + setup(); |
| 84 | + component.onUpdateAction({ field1: 'value1', field2: ['a', 'b'] } as any); |
| 85 | + expect(store.dispatch).toHaveBeenCalledWith( |
| 86 | + new UpdateDraft('draft-1', { registration_responses: { field1: 'value1', field2: ['a', 'b'] } }) |
| 87 | + ); |
94 | 88 | }); |
95 | 89 |
|
96 | | - it('should navigate to ../metadata on onBack', () => { |
| 90 | + it('should navigate back to metadata on onBack', () => { |
| 91 | + setup(); |
97 | 92 | component.onBack(); |
98 | 93 | expect(mockRouter.navigate).toHaveBeenCalledWith( |
99 | 94 | ['../', 'metadata'], |
100 | 95 | expect.objectContaining({ relativeTo: expect.anything() }) |
101 | 96 | ); |
102 | 97 | }); |
103 | 98 |
|
104 | | - it('should navigate to ../review on onNext', () => { |
| 99 | + it('should navigate to review on onNext', () => { |
| 100 | + setup(); |
105 | 101 | component.onNext(); |
106 | 102 | expect(mockRouter.navigate).toHaveBeenCalledWith( |
107 | 103 | ['../', 'review'], |
108 | 104 | expect.objectContaining({ relativeTo: expect.anything() }) |
109 | 105 | ); |
110 | 106 | }); |
111 | 107 | }); |
112 | | - |
113 | | -describe('DraftRegistrationCustomStepComponent when no draft registration', () => { |
114 | | - let component: DraftRegistrationCustomStepComponent; |
115 | | - let fixture: ComponentFixture<DraftRegistrationCustomStepComponent>; |
116 | | - |
117 | | - beforeEach(async () => { |
118 | | - await TestBed.configureTestingModule({ |
119 | | - imports: [DraftRegistrationCustomStepComponent, OSFTestingModule, MockComponent(CustomStepComponent)], |
120 | | - providers: [ |
121 | | - MockProvider(Router, RouterMockBuilder.create().build()), |
122 | | - MockProvider(ActivatedRoute, ActivatedRouteMockBuilder.create().withParams({ id: 'draft-1' }).build()), |
123 | | - provideMockStore({ |
124 | | - signals: [ |
125 | | - { selector: RegistriesSelectors.getStepsData, value: {} }, |
126 | | - { selector: RegistriesSelectors.getDraftRegistration, value: null }, |
127 | | - ], |
128 | | - }), |
129 | | - ], |
130 | | - }).compileComponents(); |
131 | | - |
132 | | - fixture = TestBed.createComponent(DraftRegistrationCustomStepComponent); |
133 | | - component = fixture.componentInstance; |
134 | | - fixture.detectChanges(); |
135 | | - }); |
136 | | - |
137 | | - it('should compute empty filesLink provider and projectId', () => { |
138 | | - expect(component.filesLink()).toBe(''); |
139 | | - expect(component.provider()).toBe(''); |
140 | | - expect(component.projectId()).toBe(''); |
141 | | - }); |
142 | | -}); |
0 commit comments