I have the following test:
const mockedObject = {
mockedMethod: jest.fn((someKey, someValue) => {
return {someKey: 'someValue'}
})
};
jest.doMock('../myObject', () => {
return mockedObject;
});
testedObject.testedMethod();
expect(mockedObject.mockedMethod).toHaveBeenCalled();
Here, in the testedObject, I am importing myObject. I would like to mock that import and pass mockedObject instead.
After looking at this question and this question, I think the above code should be good, however mockedObject.mockedMethod is never called even though testedObject is making the call.
So what is wrong with the mocking done in this test?
You call
testedObject.testedMethod()
but expect
mockedObject.mockedMethod)
try this code:
const mockedObject = {
testedMethod: jest.fn((someKey, someValue) => {
return {someKey: 'someValue'}
})
};
jest.doMock('../myObject', () => {
return mockedObject;
});
testedObject.testedMethod();
expect(mockedObject.testedMethod).toHaveBeenCalled();
I can think of some choices.
One thing that could be happening is that you are mocking the import after your tested object has required it and you cannot modify that. If that is your case, then make sure you make the instance of the object only after you have modified the package.
Another option is to create a folder mocks and create a file .js called exactly like your module or import and then return whatever you need. This works best for global dependencies.
Lastly, what you also can do is to make your tested object receive the dependency as a parameter, so you can override the import inside the file.
Hope it helps
Related
In React server components official GitHub example repo at exactly in this line here they are using response.readRoot().
I want to create a similar app for testing something with RSC's and it seems like the response does not contain the .readRoot() function any more (because they have updated that API in the react package on npm and I cannot find anything about it!). but it returns the tree in value property like below:
This means that whatever I render in my root server component, will not appear in the browser if I render that variable (JSON.parse(value) || not parsed) inside of my app context provider.
How can I render this?
Basically, if you get some response on the client side (in react server components) you have to render that response in the browser which has the new state from server but since I don't have access to readRoot() any more from response, what would be the alternative for it to use?
I used a trick o solve this issue, but one thing to keep in mind is that they are still unstable APIs that react uses and it's still recommended not to use React server component in the production level, uses it for learning and test it and get yourself familiar with it, so back to solution:
My experience was I had a lot of problems with caching layer they are using in their depo app. I just removed it. My suggestion is to not use it for now until those functions and APIs become stable. So I Removed it in my useServerResponse(...) function, which in here I renamed it to getServerResponse(...) because of the hook I created later in order to convert the promise into actual renderable response, so what I did was:
export async function getServerResponse(location) {
const key = JSON.stringify(location);
// const cache = unstable_getCacheForType(createResponseCache);
// let response = cache.get(key);
// if (response) return response;
let response = await createFromFetch(
fetch("/react?location=" + encodeURIComponent(key))
);
// cache.set(key, response);
return response;
}
and then creating a hook that would get the promise from the above function, and return an actual renderable result for me:
export function _useServerResponse(appState) {
const [tree, setTree] = useState(null);
useEffect(() => {
getServerResponse(appState).then((res) => {
setTree(res);
});
}, [appState]);
return { tree };
}
and finally in my AppContextProvider, I used that hook to get the react server component tree and use that rendered tree as child of my global context provider in client-side like below:
import { _useServerResponse } from ".../location/of/your/hook";
export default function AppContextProvider() {
const [appState, setAppState] = useState({
...someAppStateHere
});
const { tree } = _useServerResponse(appState);
return (
<AppContext.Provider value={{ appState, setAppState }}>
{tree}
</AppContext.Provider>
);
}
I know that this is like a workaround hacky solution, but it worked fine in my case, and seems like until we get stable APIs with proper official documentation about RSCs, it's a working solution for me at least!
I wanted to create a sevice-like hook that doesn't hold state, it just exports an object with funtions.
I first started with this:
export default useFoo = () => ({ // some functions here... });
But then I realized that this wouldn't be the best approach because a new object is going to be created every time the hook is called and I don't want that - I need one global object with the same reference across all components, so then I tried this:
const foo = { // some functions here... };
export default useFoo = () => foo;
It works as expected, but I'm not sure if it's the right way to do it. Is there a better way to achieve this? Or should I use context maybe?
EDIT: I know that I can just export a plain JS object and not bother myself with hooks, but I need it to be a hook because I use other hooks inside.
It works as expected, but I'm not sure if it's the right way to do it. Is there a better way to achieve this?
If foo never changes, and doesn't need to close over any values from the other hooks you're calling in useFoo, then that's fine. If it does need to change based on other values, then you can use useCallback and/or useMemo to only recreate the object when relevant things change.
export default useFoo = () => {
const something = useSomeHook();
const foo = useMemo(() => {
return { /* some functions that use `something` */ }
}, [something]);
return foo;
}
I want to get my authToken which located in
cookies.
But when I tried to get it, I got undefined or something like this.
I wanted to use useContext and put _app in the context(to check if the user is authorized in child elements), but I can't get the cookie in any way.
I can get cookie in following code that located in adminPanel element, but I don't want to break the DRY principle. Maybe you can recommend me some methods to get global context for auth? (without next-auth or something like
export async function getServerSideProps(ctx) {
if (ctx.req) {
axios.defaults.headers.get.Cookie = ctx.req.headers.cookie
return {
props: {
cookie: ctx.req.headers.cookie ? ctx.req.headers.cookie : ''
}
}
}
I tried to get at least something similar to the authorization token in _app, but nothing worked (i also tried getServerSideProps).
export async function getInitialProps(ctx) {
return {
props:{
ctx
}
}
}
In this case I got ctx: undefined...
Maybe you can recommend me some methods to get global context for auth? (without next-auth or something like that)
There's a lot to this question, so forgive me if I fail to answer directly, please let me know if you need further elaboration.
Firstly, there is a helper package for using cookies in next: https://www.npmjs.com/package/next-cookies
Secondly, if you want to keep your getServerSideProps DRY, you can always make a reusable function or a HOC wrapper and load it into whichever pages need it.
Thirdly, getting the context is slightly different for _app.jsx than it is to regular pages. The page-context is wrapped in an app-context, like so:
import App from "next/app";
class MyApp extends App {
//...
}
MyApp.getInitialProps = async (appCtx) => {
const appProps = await App.getInitialProps(appCtx);
const { ctx } = appCtx;
console.log(ctx);
// todo: get your data from ctx here
};
But beware, this will kill the static optimisation for your entire site, so it's best to keep it to just each page that needs it.
I am new to JavaScript testing and currently trying to write some test cases for a store (just an ES6 class) I created. I am using Jest as this is what we usually use for React projects, although here I am not testing a React Component but just a class wrapping a functionality.
The class I am testing extends another class, and has various methods defined in it. I want to test these methods (whether they are called or not), and also whether the properties declared in the class change as and when the corresponding class methods are called.
Now I have read about mocking functions, but from what I understand, they can only do checks like how many times a function is called, but can't replicate the functionality. But in my case, I need the functionality of the methods because I will be checking the class member values these methods change when called.
I am not sure if this is the right approach. Is it wrong to test functions in Jest without mocking? And inferentially, to test the internal workings of functions? When do we mock functions while testing?
The issue I am facing is that the project I am working on is a large one where there are multiple levels of dependencies of classes/functions, and it becomes difficult to test it through Jest as it will need to go through all of them. As I am using alias for file paths in the project, Jest throws errors if it doesn't find any module. I know its possible to use Webpack with Jest, but many of the dependent classes/functions in the code are not in React, and their alias file paths are not maintained by Webpack.
import { getData } from 'service/common/getData';
class Wrapper extends baseClass {
someVariable = false;
payload = null;
changeVariable() {
this.someVariable = true;
}
async getData() {
super.start();
response = await fetchData();
this.payload = response;
super.end();
}
}
This is a small representation of the actual code I have. Can't post the entire class here as I am working on a remote machine. Basically, I want to test whether changeVariable gets called when invoked, and whether it successfully changes someVariable to true when called; and similarly, check the value of payload after network request is complete. Note that fetchData is defined in some other file, but is critical to testing getData method. Also the path used here (service/common/getData) for importing getData is not the absolute path but an alias NOT defined in Webpack, but somewhere else. Jest can't resolve getData because of this. I will not have to worry about this if I mock getData, but then I will not be able to test its functionality I believe.
#maverick It's perfectly okay to test your class methods using jest. Check the code example in the link -
https://repl.it/repls/ClumsyCumbersomeAdware
index.js
class Wrapper {
constructor(){
this.someVariable = false;
}
changeVariable(){
this.someVariable = true;
}
getData(){
return new Promise(resolve => resolve('some data'));
}
}
module.exports = Wrapper;
index.test.js
const Wrapper = require('./index');
const wrapper = new Wrapper();
describe('Wrapper tests', () => {
it('should changeVariable', () => {
wrapper.changeVariable();
expect(wrapper.someVariable).toBe(true);
});
it('should get some data', () => {
wrapper.getData().then( res => expect(res).toBe('some data'));
});
});
This is a very simplistic example and in real life the async calls are much more complicated and dependent of 3rd party libraries or other project modules. In such cases it makes sense to have all the dependencies injected in out class and then mocked individually. For Example -
class GMapService {
constructor(placesApi, directionApi){
this.placesApi = placesApi;
this.directionApi = directionApi;
}
getPlaceDetails(){
this.placesApi.getDetails('NYC');
}
getDirections(){
this.directionApi.getDirections('A', 'B');
}
}
Now you can easily mock placesApi and directionApi, and test them individually without actually requiring Google Map dependencies.
Hope this helps ! 😇
I have a method which uses an ElementRef which is defined below.
#ViewChild('idNaicsRef') idNaicsRef: ElementRef;
ElementRef then sets the focus using .nativeElement.focus().
The method fails while running the spec, saying 'undefined is an object'
Although httpNick's answer should work, I ended up asking an architect on my team about this and he led me to a slightly different solution that may be a bit simpler.
describe(MyComponent.name, () => {
let comp: MyComponent;
describe('myFunction', () => {
it('calls focus', () => {
comp.idNaicsRef = {
nativeElement: jasmine.createSpyObj('nativeElement', ['focus'])
}
comp.myFunction();
expect(comp.idNaicsRef.nativeElement.focus).toHaveBeenCalled();
});
});
This particular example would just test to see if the focus method has been called or not. That's the test that I was interested in when I was testing my method, but you could of course test whatever you wanted. The key is the setup beforehand (which was elusive before it was shown to me).
this should work. this just creates a spy object and then you can populate it with whatever you want, so you could even check if it was called in your unit test.
import createSpyObj = jasmine.createSpyObj;
comp.idNaicsRef = createSpyObj('idNaicsRef', ['nativeElement']);
comp.idNaicsRef.nativeElement = { focus: () => { }};
comp is the reference to the component you are testing.
createSpyObj comes from a jasmine import