Trying to test my button that runs a function asynchronously. Here is the logic for my button:
// Function below will run when user clicks the button
this._pageModule.favoriteButtonCallback = async () => {
try {
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,
);
}
};
And here is my test:
fit('should be able to add the restaurant to favorite', async () => {
expect((await RestaurantIdb.GetAllRestaurant()).length).toEqual(0);
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');
favoriteButton.dispatchEvent(new Event('click'));
const restaurants = await RestaurantIdb.GetAllRestaurant();
console.log('console log from test', restaurants);
expect(restaurants).toEqual([restaurant]);
});
I'm using lit-element which is similar to react. I have a custom element <define-module> with a button inside. After giving it the required properties, it will render.
This is the test log Test log
The issue is that the console log from the test runs before the console log in the button, showing an empty array. I want the next line in the test to wait until the asynchronous function in the button is done. How can I achieve this?
What I've tried: - Console logging - Using Jasmine's done method, but it doesn't work due to async/await in the test - Trying spyOn, but unsure about spying on IndexedDB
UPDATE
I found what caused the problem and simplified my code:
/* 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);
});
});
And here is the result Test Result
IndexedDB takes time to put my restaurant data, and I am still figuring out how to fix it.