I want to convert my mock implementation for path (specifically "join") in to a __mocks__ folder in a file called path.js
Currently I have this in my io.test.js file and it works:
vi.mock("path", () => {
return {
default: {
join: (...args) => {
return args[args.length - 1];
},
},
};
});
How would I do this in the __mocks__\path.js file instead?
Vitest would normally look for the mock file with the same name as the mocked one in the __mocks__ folder under the project root folder. However I've found this a bit problematic, as on one hand having an additional root folder like that, instead for example one under test folder may not be what everyone wants (ugly?), but more importantly sometimes the name of the original import is not trivial to guess, e.g. for modules from node_modules, most the time the import path may not really be a filename, so what the file under __mocks__ should be called can become tedious guess-game...
Instead one can use this syntax to use a file based mock from any location:
// The test file
vi.mock('path', async () =>
await vi.importActual('another/path/to/the/mock.js')
)
// another/path/to/the/mock.js
export default {
join: (...args) => {
return args[args.length - 1];
},
}
Having it set up like this you can put the mock file anywhere you want.
Note that mocks under the root __mocks__ would however be automatically picked up by Vitest, so using the same folder for these kind of manual mocks can lead to confusion. I'd recommend puting them under another folder. For me test/vitest/mocks or similar seems more logical.
Related
I have a problem in a Storybook addon I created.
CURRENT SCENARIO
The issue occurs in the Storybook addon environment when a random function is imported (let's call it getSomeData) from a file (let's call it lib.ts) that contains other functions who require .md files with dynamic paths (for example a README.md file)
lib.ts
const getSomeData = () => {
...
return ...
}
export const getPackageReadme = (packageName: string) => {
try {
return require(`#namespace/${packageName}/README.md`)
} catch {
return null
}
}
These dynamic requires that import these .md files as README.md are executed in compile time by Storybook engine.
The weird fact is that in the log of Storybook it seems that this function is executed and read all .md files with the exact name README.md living everywhere in the current repository, also inside node_modules, giving an exact amount of errors as the amount of all found README.md files in the current repository. And consequence, Storybook build fails.
While this error occurs in compiling time of Storybook, at runtime in the browser any issue occurs and everything work as expected.
CURRENT SOLUTION
The current solution -that smells of a hook- to fix the issue was to split this lib.ts in different files (for examples lib-md.ts and lib-data.ts).
In this way, the Storybook addon includes just lib-data.ts and in this way any README.md file is required in compile time, so build succeeds.
lib-data.ts
const getSomeData = () => {
...
return ...
}
lib-md.ts
export const getPackageReadme = (packageName: string) => {
try {
return require(`#namespace/${packageName}/README.md`)
} catch {
return null
}
}
Is there a solution to prevent this error?
I have the map+tilemap project created in a 3rd-party app. The whole project is a set of files, the main file (XML) representing the 2D game level map and some other files (subfiles) representing graphics and tilemaps.
I am trying to create a Webpack Loader that will compile and convert the whole map/tilemap project into JSON object, that is comfortable to use in javascript. And I still can't get how to:
How can I access subfiles (taken from relative paths from the main file), what is the way to access the current directory (where the main file is placed), and the name of the main file?
How can I explain to Webpack to track changes in all subfiles, so it will run the loader again automatically to compile the whole map/tilemap project (partial re-packing).
I spent 2 days to find any working solutions, it is possible at all?
Thanks a lot!
For the first question, webpack loader is expose the file info by this, you can do like this:
module.exports = function (source) {
const loaderContext = this;
const { sourceMap, rootContext, resourcePath } = loaderContext;
const sourceRoot = path.dirname(path.relative(context, resourcePath));
...
}
For the second question, i think that maybe you can use the module.hot to track the subfiles change, like this:
if (module.hot) {
module.hot.accept('filepath', ()=>{
...
})
}
What I'm trying do is make a handler that will read a folder that it is in. However, this handler is a module that will be imported into multiple folders.
For example, if given the current directory:
->Main
->folder a
->languages
a.js
->folder b
->languages
b.js
->folder c
->languages
c.js
d.js
d.js - handler used in a.js, b.js and c.js
var Translate = ((lang) => {
// this line below is what I want to know how to do.
import { lang } from "./languages/"+lang;
// do stuff with lang
}
export { Translate }
With the d.js handler, it should be able to be used in a.js/b.js/c.js. However I want to know how to read the directory (in this case the language folder) it is being imported in rather than from the handler. I'm doing this to handle multiple languages for an app, and I figure this way its a lot easier to manage.
If you are executing the code in NodeJS environment, you can use this to get the current directory name:
import path from "path";
const dirName = path.basename(path.dirname(filename));
The dirName variable will contain the folder name as a string.
Then you can dynamically import using ES6 template literal.
import { lang } from `./languages/${dirname}`
I have some utils functions that I'm using among various Jest tests, for example a function like this, for mocking a fetch response:
export const mockFetchJsonResponse = (data) => {
ok: () => true,
json: () => data
};
I would like to share those functions in a way that I can import them and reuse among my tests. For example:
// Some .spec.jsx file
// ...
import {mockFetchJsonResponse} from 'some/path/to/shared/tests/utils.jsx'
// Then I can use mockFetchJsonResponse inside this test
// ...
Where should I place such common utils functions?
My project folder looks like this:
components/
CompOne/
__tests__
index.jsx
CompTwo/
__tests__
...
utils/
__tests__
http.js
user.js
...
Should I place them inside the utils folder together with other utils functions that I use for my project? Then should I write unit tests also for these functions?
There is an ability to expose helpers as global functions without any need to import modules explicitly.
Jest allows to configure some files will be run before every test file executed through setupFiles configuration option
Also Jest provides global object that you can modify and everything you put there will be available in your tests.
Example
package.json:
"jest": {
"setupFiles": ["helpers.js"]
}
helpers.js:
global.mockFetchJsonResponse = (data) => {
ok: () => true,
json: () => data
};
somecomponent.test.js:
mockFetchJsonResponse(); // look mom, I can call this like say expect()!
With TypeScript
TypeScript will complain with cannot find name 'mockFetchJsonResponse'. You can fix that by adding a declaration file:
helpers.d.ts:
declare function mockFetchJsonResponse(data: any): any;
Create a new tsconfig.test.json file and add that file to the files section and extend your main tsconfig:
{
"extends": "./tsconfig.json",
"files": ["./.jest/helpers.d.ts"]
}
In your jest.config.js file, add a new global setup for ts-jest to have jest use your new tsconfig file:
// ...
globals: {
"ts-jest": {
tsconfig: "tsconfig.test.json"
}
}
// ...
Sure it does not answer you direct question "where to put the files" but it's anyway up to you. You just need specify those files in setupFiles section. Since there is no import needed in tests it does not really matter.
As for testing test helpers I'm not sure. See it's part of testing infrastructure like spec file itself. And we don't write tests for tests or it would never stop. Sure, it's up to you - say if logic behind is really-really complex and hard to follow. But if helper provides too complex/complicated logic it would lead to tests themselves be impossible to understand, do you agree?
kudos to that article on testing compoentns with intl. Have never dealt with globals in jest before.
TL;DR; create a /__utils__/ and update testPathIgnorePatterns
Full answer:
Here's just a suggestion:
testPathIgnorePatterns: ['/__fixtures__/', '/__utils__/'],
I use /__tests__/ for the tests and within it sometimes I need to add a folder with data that will be used by those tests, so I use /__fixtures__/ folder.
Likewise, when I have a shared logic across tests, I place them at /__utils__/ folder (also within /__tests__/)
For more details, please read more about testPathIgnorePatterns
Another approach is by having a test directory and moving helpers on it.
src/
components/
utils/
...
test/
testHelpers.js
Then on the test:
// src/components/MyComponent.spec.js
import { helperFn } from '../../test/testHelpers';
Benefits:
Be explicit of where the function is coming from
Separate helpers that need to be tested from those that do not ¹
Drawbacks:
The test directory might look silly by containing just a helper file
AFAIK this approach is no where specified on official documentation
Looks like GitLab is implementing this approach on their RoR project.
¹ no matter which approach you take, please don't test the test helpers. If the helper fails then your test must fail too. Otherwise your helper is not helping at all.
With this code
const noCurrencies: Map<CurrencyCode, Currency> = new Map();
/**
* Reducer for the finished currency request.
*/
export function currencies(state: Map<CurrencyCode, Currency> = noCurrencies, action: Action): Map<CurrencyCode, Currency> {
switch (action.type) {
case SET_CURRENCIES:
return action.currencies;
default:
console.log('currencies(reducer): noCurrencies', noCurrencies)
return state;
}
}
I get this console output:
currencies(reducer): noCurrencies undefined
Is this a known problem with Babel? How do I debug it? I have a feeling that it's due to this particular file having been called twice during initialisation and thus having a circular dependency with another file.
(I'm not 'recreating a repro from scratch', so don't suggest that, and the types are https://github.com/flowtype/flow-typed which get removed in a pre-processor step, and I've tried without types as well, with the same result)
The reason was a large circular dependency between modules. Even if using ECMAScript module syntax, the compiler (WebPack 3 + babel) is not smart enough to only load what is needed when it's needed; but instead evaluate all exports and imports whenever a file is used/touched.
That means that if you have index.js files that liberally export things from around them, to create a single entry-point for callers outside its folder, you'll likely run into issues like this.
I had to go through the code-base and make the imports 'deep' by directing imports straight to the, of the index file, surrounding files, instead.
E.g.
folder A
epics.js
commands.js
index.js
types.js
actions.js
reducers.js
messages.js
...
folder B
import { create } from '../A' becomes import { create } from '../A/types'
and so forth for all things; in the end I'm only exporting React views and types from index.js