繁体   English   中英

如何使用 karma-jasmine 在 function 中使用具有异步等待的单击处理程序自动测试 function?

[英]How to automate testing function with click handler that have async await inside the function using karma-jasmine?

所以我正在尝试测试异步运行 function 的按钮。 这是我的按钮逻辑。

    // Function below will run when user click the button
    this._pageModule.favoriteButtonCallback = async () => {
      try {
        // I want to expect run after this await below is done
        await this._favoriteRestaurants.PutRestaurant(this._restaurant);
        console.log(
          'console log in button',
          await this._favoriteRestaurants.GetAllRestaurant(),
        );
        this._renderButton();
        return Promise.resolve(
          `Success add ${this._restaurant.name} to favorite!`,
        );
      } catch (err) {
        this._renderButton();
        return Promise.reject(
          new Error(
            `Failed add ${this._restaurant.name} to favorite! Error: ${err}`,
          ).message,
        );
      }
    };

这是我的测试

fit('should be able to add the restaurant to favorite', async () => {
    expect((await RestaurantIdb.GetAllRestaurant()).length).toEqual(0);

    // spyOn(RestaurantIdb, 'PutRestaurant');

    document.body.innerHTML = `<detail-module></detail-module>
    <modal-element></modal-element>`;

    const pageModule = document.querySelector('detail-module');

    await FavoriteButtonInitiator.init({
      pageModule,
      restaurant,
      favoriteRestaurants: RestaurantIdb,
    });

    pageModule.restaurantDetail = restaurant;

    await pageModule.updateComplete;

    const favoriteButton = pageModule.shadowRoot
      .querySelector('[aria-label="favorite this restaurant"]')
      .shadowRoot.querySelector('button');

    // 1. Simulate user click the button
    favoriteButton.dispatchEvent(new Event('click'));

    // expect(RestaurantIdb.PutRestaurant).toHaveBeenCalled();

    const restaurants = await RestaurantIdb.GetAllRestaurant();
    console.log('console log from test', restaurants);
    expect(restaurants).toEqual([restaurant]);
  });

我正在使用 lit-element,只是它与 React 类似,我有自定义元素 <define-module>,里面有按钮。 然后我给它所需的属性,然后它就会呈现。

这是我的测试日志测试日志

如您所见,测试中的控制台日志在我放入按钮的控制台日志之前运行。 它是空数组。

我想要的是何时发送点击事件。 测试中的下一行等待按钮中的异步 function 完成,我怎样才能让它成为可能?

我做了什么:我试图通过控制台记录它们。 我曾尝试在 jasmine 中使用 done,但它不起作用,因为我在测试中使用了 async/await。 我试过使用 spyOn,但我真的不明白如何监视 indexedDb

更新

所以我找到了导致问题的原因,在这里我简化了我的代码。

/* eslint-disable */
import { openDB } from 'idb';
import { CONFIG } from '../src/scripts/globals';

const { DATABASE_NAME, DATABASE_VERSION, OBJECT_STORE_NAME } = CONFIG;

const dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
  upgrade(database) {
    database.createObjectStore(OBJECT_STORE_NAME, { keyPath: 'id' });
  },
});

const RestaurantIdb = {
  async GetRestaurant(id) {
    return (await dbPromise).get(OBJECT_STORE_NAME, id);
  },
  async GetAllRestaurant() {
    return (await dbPromise).getAll(OBJECT_STORE_NAME);
  },
  async PutRestaurant(restaurant) {
    if (await this.GetRestaurant(restaurant.id)) {
      return Promise.reject(
        new Error('This restauant is already in your favorite!').message,
      );
    }
    return (await dbPromise).put(OBJECT_STORE_NAME, restaurant);
  },
  async DeleteRestaurant(id) {
    if (await this.GetRestaurant(id)) {
      return (await dbPromise).delete(OBJECT_STORE_NAME, id);
    }
    return Promise.reject(
      new Error('This restauant is not in favorite!').message,
    );
  },
};

describe('Testing RestaurantIdb', () => {
  const removeAllRestaurant = async () => {
    const restaurants = await RestaurantIdb.GetAllRestaurant();

    for (const { id } of restaurants) {
      await RestaurantIdb.DeleteRestaurant(id);
    }
  };

  beforeEach(async () => {
    await removeAllRestaurant();
  });

  afterEach(async () => {
    await removeAllRestaurant();
  });

  it('should add restaurant', async () => {
    document.body.innerHTML = `<button></button>`;

    const button = document.querySelector('button');
    button.addEventListener('click', async () => {
      await RestaurantIdb.PutRestaurant({ id: 1 });
    });

    button.dispatchEvent(new Event('click'));

    setTimeout(async () => {
      const restaurants = await RestaurantIdb.GetAllRestaurant();
      console.log('console log in test', restaurants);

      expect(restaurants).toEqual([{ id: 1 }]);
    }, 0);
  });
});

这是结果测试结果

我假设 IndexedDb 需要时间来放置我的餐厅数据。 我仍然不知道如何解决它。

如果您使用的是 Angular,您将可以访问 fixture.whenStable fixture.whenStable()以及fakeAsync and tick() ,它们会等到 promises 被解决后再继续测试。

在这种情况下,我会尝试将测试中的内容包装在setTimeout

fit('should be able to add the restaurant to favorite', async () => {
    expect((await RestaurantIdb.GetAllRestaurant()).length).toEqual(0);

    // spyOn(RestaurantIdb, 'PutRestaurant');

    document.body.innerHTML = `<detail-module></detail-module>
    <modal-element></modal-element>`;

    const pageModule = document.querySelector('detail-module');

    await FavoriteButtonInitiator.init({
      pageModule,
      restaurant,
      favoriteRestaurants: RestaurantIdb,
    });

    pageModule.restaurantDetail = restaurant;

    await pageModule.updateComplete;

    const favoriteButton = pageModule.shadowRoot
      .querySelector('[aria-label="favorite this restaurant"]')
      .shadowRoot.querySelector('button');

    // 1. Simulate user click the button
    favoriteButton.dispatchEvent(new Event('click'));

    // expect(RestaurantIdb.PutRestaurant).toHaveBeenCalled();
    setTimeout(() => {
     const restaurants = await RestaurantIdb.GetAllRestaurant();
     console.log('console log from test', restaurants);
     expect(restaurants).toEqual([restaurant]);
    }, 0);
  });

setTimeout中的事情应该在按钮单击的异步任务之后发生,因为 promises 是微任务,而setTimeout是一个宏任务,微任务比宏任务具有更高的优先级。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM