I have created a function that allows to manage caching. I use this function to cache the responses to API calls.
export const cache = async (key: string, callback: Function) => {
const cacheKey = `cache:${key}`;
const data = await useStorage().getItem(cacheKey);
if (data) {
console.log('Get cached data for key: %s', key);
return data;
}
const result = await callback();
console.log('Caching data for key: %s', key);
await useStorage().setItem(cacheKey, result);
return result;
}
Here is a use case:
import { cache } from '~/server/lib/caching/cache-manager';
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const domain = event.context.params.domain;
const id = event.context.params.id;
const url = `${config.baseUrl}/api/${domain}/${id}`;
return await cache(url, () => {
return $fetch(url);
});
})
I would like to test the 'cache' function with vitest. For info, I added a vitest plugin to manage Nuxt aliases and auto-import, based on https://github.com/nuxt/framework/discussions/5379#discussioncomment-4224823
Here is the test, which does nothing, it just calls the 'cache' function:
import { describe, beforeEach, afterEach, test, expect, vi } from 'vitest'
import { cache } from '~/server/lib/caching/cache-manager'
describe('My test', () => {
test('my test', () => {
const result1 = cache('mykey', () => 3);
const result2 = cache('mykey', () => 3);
})
})
But I get an error when I call the cache function:
ReferenceError: useStorage is not defined
The Nitro's useStorage is not recognized.
I think the problem is related to #imports
which does not include server auto-imports.
I tested the following workaround but it still doesn't work:
https://github.com/nuxt/framework/issues/4290
You can test here:
https://stackblitz.com/edit/nuxt-starter-e3vtf2?file=tests%2Fserver%2Flib%2Fcaching%2Fcache-manager.test.ts
How can I test my 'cache' function that uses 'useStorage'?
I created a storage.ts
file which contains the useStorage
mock.
import { vi } from "vitest";
const mockedStorage = {
getItem: vi.fn(),
setItem: vi.fn()
}
export const useStorage = vi.fn(() => mockedStorage)
I created an index.ts
file that exports the mock.
export { useStorage } from './storage'
I declared the index.ts
file in the vitest configuration in order to auto import the declared modules:
...
Vue(),
autoImport.vite({
presets: [
{
package: srcDir + '/__mocks__/index.ts'
},
{
package: buildDir + '/imports.d.ts'
}
]
}),
...
If I need to auto import other mocks, I add them in index.ts
.
And I updated my test to test my cache
function:
import { describe, beforeEach, afterEach, test, expect, vi } from 'vitest';
import { cache } from '~/server/lib/caching/cache-manager';
import { useStorage } from '~/__mocks__/storage';
describe('My test', () => {
test('my test', async () => {
useStorage().getItem.mockReturnValue(3);
const result = await cache(`myKey`, () => 3);
expect(useStorage().getItem).toBeCalledWith(`cache:myKey`);
expect(result).toBe(3);
expect(useStorage().setItem).not.toBeCalled();
});
test('my test 2', async () => {
useStorage().getItem.mockReturnValue(null);
const result = await cache(`myKey`, () => 3);
expect(useStorage().getItem).toBeCalledWith(`cache:myKey`);
expect(result).toBe(3);
expect(useStorage().setItem).toBeCalledWith(`cache:myKey`, 3);
});
});
You can test here:
https://stackblitz.com/edit/nuxt-starter-tl2ecc?file=tests/server/lib/caching/cache-manager.test.ts
I would suggest proxying the function in its own module and mocking it, at least until Nuxt has a reliable solution.
For example, create a module that exports the proxied method:
// server/lib/caching/use-storage.ts
const proxyUseStorage = () => useStorage()
export { proxyUseStorage as useStorage }
In the same directory, create a __mocks__/use-storage.ts
file and mock how you see fit – for this example I'm simply re-instantiating the default in-memory storage interface:
// server/lib/caching/__mocks__/use-storage.ts
import { createStorage } from 'unstorage'
import { vi } from 'vitest'
export const useStorage = vi.fn(() => createStorage())
Explicitly import the method where it's used because you want to make sure it can later be mocked in tests:
// server/lib/caching/cache-manager.ts
import { useStorage } from './use-storage'
export const cache = async (key: string, callback: Function) => {
const cacheKey = `cache:${key}`
const data = await useStorage().getItem(cacheKey)
// ...
}
Finally, mock the module before your tests (ensuring the path used is relative to the test file):
// server/lib/caching/cache-manager.spec.ts
import { expect, test, vi } from 'vitest'
import { cache } from '~/server/lib/caching/cache-manager'
vi.mock('./use-storage')
test('cache', async () => {
expect(await cache('myKey', () => 3)).toBe(3)
})
YMMV depending on your setup, but this should give you a foundation to get mocking.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.