function getTestCases()

in spec/index.js [210:472]


  function getTestCases(viewFactory) {
    return function () {
      beforeEach(doAsync(async () => {
        listView = viewFactory({ size: 20000 });
        await render();
        listView.viewport.scrollTo({ y: 0 });
        await sleep(redrawInterval);
      }));

      afterEach(doAsync(async () => {
        listView.remove();
        await sleep(redrawInterval);
      }));

      it('should create the ListView correctly', function () {
        expect($('.test-container').get(0)).to.equal(listView.el);
        expect($('.test-container > .internal-viewport > ul > li').length).to.be.above(0);
      });

      it('should fill up the viewport', function () {
        const elLast = $('.test-container > .internal-viewport > ul > li').last().get(0);
        const rectLast = elLast.getBoundingClientRect();
        const height = viewportMetrics().outer.height;

        expect(rectLast.bottom).to.be.at.least(height);
      });

      it('should fill up the viewport after jump scrolling', doAsync(async () => {
        for (let scrollTop of [1000, 2000, 20000, 10000]) {
          listView.viewport.scrollTo({ y: scrollTop });
          await sleep(redrawInterval);

          checkViewportFillup();
        }
      }));

      it('should fill up the viewport while scrolling down continuously', doAsync(async () => {
        for (let scrollTop = 1000; scrollTop < 1500; scrollTop += 100) {
          listView.viewport.scrollTo({ y: scrollTop });
          await sleep(redrawInterval);

          checkViewportFillup();
        }
      }));

      it('should fill up the viewport while scrolling up continuously', doAsync(async () => {
        for (let scrollTop = 2000; scrollTop > 1500; scrollTop -= 100) {
          listView.viewport.scrollTo({ y: scrollTop });
          await sleep(redrawInterval);

          checkViewportFillup();
        }
      }));

      it('should be able to scroll an element to top', doAsync(async () => {
        for (let index of [0, 1, 11, 111, 1111, 11111]) {
          await scrollToItem(index, 'top');

          checkItemLocation(index, 'top');
          checkViewportFillup();
        }

        await scrollToItem(listView.options.items.length - 1, 'top');

        checkScrolledToBottom();
        checkViewportFillup();
      }));

      it('should be able to scroll an element to bottom', doAsync(async () => {
        for (let index of [11111, 11110, 11100, 11000, 10000]) {
          await scrollToItem(index, 'bottom');

          checkItemLocation(index, 'bottom');
          checkViewportFillup();
        }

        await scrollToItem(0, 'bottom');

        checkScrolledToTop();
        checkViewportFillup();
      }));

      it('should be able to scroll an element to middle', doAsync(async () => {
        for (let index of [11111, 11110, 11100, 11000, 10000]) {
          await scrollToItem(index, 'middle');

          checkItemLocation(index, 'middle');
          checkViewportFillup();
        }

        await scrollToItem(0, 'middle');

        checkScrolledToTop();
        checkViewportFillup();

        await scrollToItem(listView.options.items.length - 1, 'middle');

        checkScrolledToBottom();
        checkViewportFillup();
      }));

      it('should be able to scroll an element to certain offset', doAsync(async () => {
        const index = 1000;
        const height = viewportMetrics().outer.height;

        for (let pos of [0, 0.2, 0.5, 0.7, 0.9].map(rate => rate * height)) {
          await scrollToItem(index, pos);

          checkItemLocation(index, pos);
          checkViewportFillup();
        }
      }));

      it('should be scroll item to nearest visible location with "default" option', doAsync(async () => {
        await scrollToItem(2000);
        checkItemLocation(2000, 'bottom');

        await scrollToItem(2001);
        checkItemLocation(2001, 'bottom');

        await scrollToItem(1000);
        checkItemLocation(1000, 'top');

        await scrollToItem(999);
        checkItemLocation(999, 'top');

        listView.scrollToItem(999);
        await sleep(redrawInterval);
        checkItemLocation(999, 'top');

        const top = getElementRect(1000).top;
        await scrollToItem(1000);
        expect(Math.abs(getElementRect(1000).top - top)).to.be.below(1);
      }));

      it('should complain about wrong position opitons', function () {
        _.each([
          true,
          'some-where',
          { foo: 'bar' },
          ['foo', 'bar'],
        ], pos => {
          expect(() => listView.scrollToItem(0, pos)).to.throw('Invalid position');
        });
      });

      it('should complain about the view is not rendered', function () {
        const view = viewFactory({ size: 20000 });
        const message = 'Cannot scroll before the view is rendered';
        expect(() => view.scrollToItem(10)).to.throw(message);
      });

      it('should be able to reset the defaultItemHeight', doAsync(async () => {
        const height = viewportMetrics().inner.height;
        await set({ defaultItemHeight: 22 });
        expect(viewportMetrics().inner.height).to.be.above(height);
      }));

      it('should be able to reset the items', doAsync(async () => {
        const $ul = $('.test-container > .internal-viewport > ul');
        const text = 'hello world!';

        await set({ items: [{ text }] });
        expect($ul.children().length).to.equal(3);
        expect($ul.children().text()).to.equal(text);

        await set({ items: [] });
        expect($ul.length).to.equal(1);
        expect($ul.children().length).to.equal(2);
      }));

      it('should be able to use duck typed array as items', doAsync(async () => {
        const $ul = $('.test-container > .internal-viewport > ul');
        const prefix = 'item';

        await set({
          items: {
            length: 50000,
            slice(start, stop) {
              return _.map(_.range(start, stop), i => ({ text: `${prefix} ${i}` }));
            },
          },
        });
        expect($ul.children().first().next().text()).to.equal(`${prefix} 0`);
        checkViewportFillup();
      }));

      it('should be able to reset the model and listTemplate', doAsync(async () => {
        const title = 'New Template';
        const model = { title };
        const listTemplate = alternativeListTemplate;

        await set({ model, listTemplate });

        const $h2 = $('.test-container > h2');
        expect($h2.length).to.equal(1);
        expect($h2.text()).to.equal(title);
        checkViewportFillup();
      }));

      it('should be able to reset the itemTemplate', doAsync(async () => {
        const prefix = 'item';
        const itemTemplate = ({ text }) => `<li>${prefix} - ${text}</li>`;

        await set({ itemTemplate });

        const $ul = $('.test-container > .internal-viewport > ul');
        expect($ul.children().length).to.be.at.least(3);
        expect($ul.children().first().next().text()).to.be.equal(`${prefix} - ${listView.itemAt(0).text}`);
        checkViewportFillup();
      }));

      it('should be able to handle the DOM events', doAsync(async () => {
        const spy = sinon.spy();
        const events = { 'click li': spy };

        await set({ events });

        const $ul = $('.test-container > .internal-viewport > ul');
        $ul.children().first().next().click();
        expect(spy).to.be.calledOnce;
      }));

      it('should be able to handle the ListView events', doAsync(async () => {
        const spyWillRedraw = sinon.spy();
        const spyDidRedraw = sinon.spy();
        const events = { willRedraw: spyWillRedraw, didRedraw: spyDidRedraw };

        await set({ events });
        expect(spyWillRedraw).have.been.calledOnce;
        expect(spyDidRedraw).have.been.calledOnce;

        await scrollToItem(1000);
        expect(spyWillRedraw).have.been.calledTwice;
        expect(spyDidRedraw).have.been.calledTwice;

        await set({ events: {} });
        expect(spyWillRedraw).have.been.calledTwice;
        expect(spyDidRedraw).have.been.calledTwice;

        await scrollToItem(0);
        expect(spyWillRedraw).have.been.calledTwice;
        expect(spyDidRedraw).have.been.calledTwice;
      }));

      it('should invoke the callback immediatedly if reset with no valid options', function () {
        const spy = sinon.spy();

        listView.set({ foo: 'bar' }, spy);
        expect(spy).to.be.calledOnce;
      });

      it('should be able to invalidate the rendered items', doAsync(async () => {
        const $ul = $('.test-container > .internal-viewport > ul');
        const elFirst = $ul.children().get(1);

        await new Promise(resolve => listView.invalidate(resolve));

        const elFirstNew = $ul.children().get(1);
        expect(elFirstNew).not.to.equal(elFirst);
      }));
    };
  }