Как смоделировать window.screen.width в угловом модульном тесте с жасмином - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть BreakpointService, который говорит мне - в зависимости от ширины экрана - в каком SidebarMode (закрыто - минимизировано - открыто) я должен отобразить свою боковую панель.

Это основная часть услуги:

constructor(private breakpointObserver: BreakpointObserver) {
    this.closed$ = this.breakpointObserver.observe(['(min-width: 1024px)']).pipe(
      filter((state: BreakpointState) => !state.matches),
      mapTo(SidebarMode.Closed)
    );

    this.opened$ = this.breakpointObserver.observe(['(min-width: 1366px)']).pipe(
      filter((state: BreakpointState) => state.matches),
      mapTo(SidebarMode.Open)
    );

    const minifiedStart$: Observable<boolean> = this.breakpointObserver.observe(['(min-width: 1024px)']).pipe(map(state => state.matches));

    const minifiedEnd$: Observable<boolean> = this.breakpointObserver.observe(['(max-width: 1366px)']).pipe(map(state => state.matches));

    this.minified$ = minifiedStart$.pipe(
      flatMap(start => minifiedEnd$.pipe(map(end => start && end))),
      distinctUntilChanged(),
      filter(val => val === true),
      mapTo(SidebarMode.Minified)
    );

    this.observer$ = merge(this.closed$, this.minified$, this.opened$);
  }

с помощью этой строки я могу подписаться на события:

this.breakpointService.observe().subscribe();

Теперь я хотел бы протестировать различные режимы внутри юнит-теста, но я не знаю

как смоделировать свойство window.screen.width в тесте

Я попробовал несколько вещей, но у меня ничего не получилось.

Это моя тестовая установка:

describe('observe()', () => {
    function resize(width: number): void {
      // did not work
      // window.resizeTo(width, window.innerHeight);
      // (<any>window).screen = { width: 700 };
      // spyOn(window, 'screen').and.returnValue(...)
    }

    let currentMode;
    beforeAll(() => {
      service.observe().subscribe(mode => (currentMode = mode));
    });

    it('should return Observable<SidebarMode>', async () => {
      resize(1000);

      expect(Object.values(SidebarMode).includes(SidebarMode[currentMode])).toBeTruthy();
    });

    xit('should return SidebarMode.Closed', async () => {
      resize(600);

      expect(currentMode).toBe(SidebarMode.Closed);
    });

    xit('should return SidebarMode.Minified', async () => {
      resize(1200);

      expect(currentMode).toBe(SidebarMode.Minified);
    });

    xit('should return SidebarMode.Open', async () => {
      resize(2000);

      expect(currentMode).toBe(SidebarMode.Open);
    });
  });

1 Ответ

0 голосов
/ 13 ноября 2018

Насмешливый угловой материал BreakpointObserver

Полагаю, вы на самом деле не хотите издеваться над window.screen, на самом деле вы хотите издеваться BreakpointObserver. В конце концов, нет необходимости тестировать их код, вы просто хотите проверить, правильно ли ваш код реагирует на наблюдаемое, возвращаемое BreakpointObserver.observe() с различными размерами экрана.

Есть много разных способов сделать это. Чтобы проиллюстрировать один метод, я собрал STACKBLITZ с вашим кодом, показывающим, как я подхожу к этому. Стоит отметить, что они отличаются от того, что написано в вашем коде:

  • Ваш код устанавливает наблюдаемые в конструкторе. Из-за этого макет должен быть изменен ДО создания экземпляра службы, поэтому вы увидите, что вызов resize() происходит до вызова service = TestBed.get(MyService);.
  • Я высмеял BreakpointObserver с помощью spyObj и назвал подделкой функция вместо метода BreakpointObserver.observe(). это фальшивая функция использует фильтр, который я настроил с результатами, которые я хотел из различных матчей. Все они начались как ложные, потому что значения будут меняться в зависимости от того, какой размер экрана желательно высмеивается, и это устанавливается с помощью функции resize(), которую вы использовали в приведенном выше коде.

Примечание: конечно, есть и другие способы приблизиться к этому. Проверьте собственные угловые материалы breakpoints-observer.spec.ts на github . Это гораздо более приятный общий подход, чем тот, который я здесь изложил, который заключался в том, чтобы просто протестировать предоставленную вами функцию.

Вот фрагмент из предложенного StackBlitz новой предложенной функции describe:

describe('MyService', () => {
    let service: MyService;
    const matchObj = [ // initially all are false
      { matchStr: '(min-width: 1024px)', result: false },
      { matchStr: '(min-width: 1366px)', result: false },
      { matchStr: '(max-width: 1366px)', result: false }
    ];
    const fakeObserve = (s: string[]): Observable<BreakpointState> => from(matchObj).pipe(
        filter(match => match.matchStr === s[0]),
        map(match => <BreakpointState>{ matches: match.result, breakpoints: {} })
    );
    const bpSpy = jasmine.createSpyObj('BreakpointObserver', ['observe']);
    bpSpy.observe.and.callFake(fakeObserve);
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [  ],
            providers: [ MyService, 
            { provide: BreakpointObserver, useValue: bpSpy }
            ]
        });
    });

    it('should be createable', () => {
        service = TestBed.get(MyService);
        expect(service).toBeTruthy();
    });

    describe('observe()', () => {
        function resize(width: number): void {
          matchObj[0].result = (width >= 1024) ? true : false;
          matchObj[1].result = (width >= 1366) ? true : false;
          matchObj[2].result = (width <= 1366) ? true : false;
        }

        it('should return Observable<SidebarMode>', () => {
            resize(1000);
            service = TestBed.get(MyService);
            service.observe().subscribe(mode => {
                expect(Object.values(SidebarMode).includes(SidebarMode[mode])).toBeTruthy();
            });
        });

        it('should return SidebarMode.Closed', () => {
            resize(600);
            service = TestBed.get(MyService);
            service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Closed));
        });

        it('should return SidebarMode.Minified', () => {
            resize(1200);
            service = TestBed.get(MyService);
            service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Minified));
        });

        it('should return SidebarMode.Open', () => {
            resize(2000);
            service = TestBed.get(MyService);
            service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Open));
        });
    });
});

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...