【问题标题】:How to test ngrx store action dispatch on route params change?如何在路由参数更改时测试 ngrx 商店操作调度?
【发布时间】:2020-02-11 20:35:10
【问题描述】:

我正在测试一个组件,当单击按钮时,该组件会显示来自 ngrx 存储的一些数据。

点击按钮,路由参数改变

  <button
    class="submit"
    [routerLink]="['/page']"
    [queryParams]="{
      period_start: '01.01.19',
      period_end: '01.01.19',
      submit_search: '->'
    }"
  >
  </button>

如果其中一个参数是 submit_search,我会在 init 上订阅路由参数的更改并调度存储操作。运行测试时不会记录任何文本。

  ngOnInit() {
    this.route.queryParams.subscribe(params => {
      console.log('Before params.submit_search');
      if (params.submit_search) {
        console.log('In params.submit_search');
        this.store.dispatch(...);
      }
    });
  }

这个测试知道点击后的路由已经改变(这个测试通过了):

    it('should set route params to filter params', fakeAsync(() => {
      const filterButtonElement = fixture.nativeElement.querySelector('.submit');
      filterButtonElement.click();
      tick();
      expect(location.path()).toEqual(
        `'/page?period_start=01.01.19&period_end=01.01.19&submit_search=-%3E'`
      );
    }));

但是这个测试说'dispatch'已经被调用了0次,所以订阅还没有注册路由的变化:

describe('SomeComponent', () => {
  let dispatchSpy;
  let location: Location;
  let router: Router;
  let route: ActivatedRoute;
  let component: SomeComponent;
  let fixture: ComponentFixture<SomeComponent>;
  let mockStore: MockStore<State>;
  let mockGetData: MemoizedSelector<State, SomeData[]>;
  const initialState = {};
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        RouterTestingModule.withRoutes([
          {
            path: 'page',
            component: SomeComponent
          }
        ]),
      ],
      declarations: [SomeComponent],
      providers: [
        provideMockStore({ initialState }),
        { provide: ActivatedRoute, useValue: { queryParams: from([]) } }
      ]
    }).compileComponents();
    router = TestBed.get(Router);
    route = TestBed.get(ActivatedRoute);
    location = TestBed.get(Location);
  }));
  beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    mockStore = TestBed.get(Store);
    mockGetData = mockStore.overrideSelector(SomeSelectors.selectData, []);
    router.initialNavigation();
    fixture.detectChanges();
  });
    it('should dispatch store action', fakeAsync(() => {
      dispatchSpy = spyOn(mockStore, 'dispatch');
      const filterButtonElement = fixture.nativeElement.querySelector('.submit');
      filterButtonElement.click();
      tick();
      expect(dispatchSpy).toHaveBeenCalledTimes(1);
    }));
});

为什么没有触发订阅? 我应该以不同的方式提供 ActivatedRoute 参数吗?

【问题讨论】:

  • if(params.submit_search) 中添加一个console.log('In params.submit_search') 并在spyOn(mockStore, 'dispatch'); 之前添加一个console.log('Before spying');,并确保In params.submit_searchBefore spying 之后而不是之前被记录。如果运行测试时出现 Chrome 或浏览器,您可以在同一位置(在 if 语句之后)放置 debugger; 并查看它是否也被触发。这很难,因为我看不到你拥有的一切。
  • 路由参数订阅中没有记录,所以订阅是问题

标签: angular testing ngrx


【解决方案1】:

看来您必须将ActivatedRoute 模拟成您想要的。

ActivatedRoute 的提供更改为这样,这有望让您畅通无阻。

  import { of } from 'rxjs';
  //.....
  providers: [.... 
              {
                 provide: ActivatedRoute, 
                 useValue: { queryParams: of({ submit_search: 'hello', })
               }],

现在要想办法改变queryParams的值,你可以这样做:

let dispatchSpy;
let queryParamsValue = new BehaviorSubject({ submit_search: 'hello', });
....
// bind this behavior subject to queryParams in the provider
  useValue: { queryParams: queryParamsValue }

然后在您的测试中,您可以通过queryParamsValue.next({ ... }); 更改queryParams 的值并开始订阅。

【讨论】:

  • 谢谢,这很有效 :) 我有点想它应该在点击按钮时自动启动子,而不需要我手动更改参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
  • 2018-10-24
  • 2016-09-21
  • 2023-03-25
  • 2019-08-19
  • 1970-01-01
相关资源
最近更新 更多