[英]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.