Let me start by saying that I am new to React and even newer to TDD coding in JavaScript. I am currently working on a React / Redux application where we are testing all of our components. Our current test suite consists of Jasmine, Mocha, Chai, Karma, and skin-deep. For some of our components we are using skin-deep (see below -- skin deep is )
import sd from 'skin-deep';
describe('testing-text-editor', () => {
let tree;
let instance;
let vdom;
let field;
let fieldInput;
let callbackFunction;
beforeEach(() => {
field = 'description';
fieldInput = '<div>I am the description</div>';
callbackFunction = () => console.log('foo');
tree = sd.shallowRender(React.createElement(TextEditor, { id: field, initialValue: fieldInput, onSubmit: callbackFunction }));
instance = tree.getMountedInstance();
vdom = tree.getRenderOutput();
});
it('testing-render-description', function() {
// some tests
});
})
Whenever we use skin-deep we are using it on components where we also use shallowRender. I was wondering if anyone has a good understanding of what skin-deep is really doing? I've been searching all morning for a good description of its functionality and purpose but am yet to find a satisfying answer.
EDIT: Moved some logic to the beforeEach to be more descriptive with my problem
Thanks!
Related
I am trying to create an easing function on scroll but my main function is growing rather large and I want to be able to split it up. I am creating a requestAnimationFrame function that will ease the page scroll. The big issue I am having is that the render function with the animation frame will ease the Y value and then calls the update function to update the elements. But if I split this up and import them individually I am having trouble figuring out how to pass the updated values between functions. Many other functions also rely on these updated values.
I could take an object oriented approach and create a class or a constructor function and bind this to the function but it seems like bad practice to me:
import render from './render'
import update from './update'
const controller = () => {
this.items = [];
this.event = {
delta: 0,
y: 0
}
this.render = render.bind(this)
this.update = update.bind(this)
//ect
}
I could also break it up into classes that extend each other but I would like to take a more functional approach to the situation but I am having trouble figuring out how to achieve this.
Here is a very condensed version of what I am trying to do. Codesandbox.
const controller = (container) => {
const items = [];
let aF = null;
const event = {
delta: 0,
y: 0
};
const render = () => {
const diff = event.delta - event.y;
if (Math.abs(diff) > 0.1) {
event.y = lerp(event.y, event.delta, 0.06);
aF = requestAnimationFrame(render);
} else {
stop();
}
update();
};
const start = () => {
if (!aF) aF = requestAnimationFrame(render);
};
const stop = () => {
event.y = event.delta;
cancelAnimationFrame(aF);
aF = null;
};
const update = () => {
const y = event.y;
container.style.transform = `translateY(-${y}px)`;
items.forEach((item) => {
item.style.transform = `translate(${y}px, ${y}px)`;
});
};
const addItem = (item) => items.push(item);
const removeItem = (item) => {
const idx = items.indexOf(item);
if (idx > -1) items.splice(idx, 1);
};
const onScroll = () => {
event.delta = window.scrollY;
start();
};
// and a bunch more stuff
window.addEventListener("scroll", onScroll);
return {
addItem,
removeItem
};
};
export default controller;
I would like to be able to split this up and create a more functional approach with pure functions where I can import the update and render functions. The problem is that these functions are reliant on the updated global variables. Everywhere I look it says that global variables are a sin but I don't see a way to avoid them here. I have tried to look at the source code for some large frameworks to get some insight on how they structure their projects but it is too much for me to take in at the moment.
Any Help would be appreciated. Thanks.
What you wrote in the first example is completely valid, you basically did what classes are doing under the hood (classes are just syntactic sugar almost), but there are some problems with your code:
You use an arrow function, so this becomes window actually in that context.
You should use function expression instead, and initialize your instance using new, only in this case this will work how you want.
However, there are many solutions for Dependency Injection / Plugin systems which is what you're basically looking for, I'd advise you to look around this area.
In case you want a more functional approach, you need to avoid the this keyword and you need to use pure functions. I'd advice you not to share values in a context, but simply pass the necessary dependencies to your functions.
import render from './render'
const controller = () => {
const items = []
window.addEventListener('scroll', (event) => {
start({ y: event.y })
})
const start = ({ y }) => {
// Pass what render needs
requestAnimationFrame(() => render({ container, items, y }))
}
}
Using the above:
You don't need the update function in this file, render will import it on its own.
Your functions are pure, easily testable on their own.
You don't need to create an instance by using new (it's actually more expensive).
No need for shared state across functions.
No DI/Plugin solution need to implemented/used.
In case you do want to have shared state, you won't do that without classes and/or extra tooling around.
The way I'd do this is by creating a seperate .js file, then send the information you need into that js file right at the start of your main files code. Then just use the seperate file to store all your functions, then just call them with utils.myFunction(). At least that's how I do it in node.
Im using react hooks and using Use State for component states. While testing the component in jest i see i cant access state value and mock it either.
There are bunches of code which is looking for different values in state. since state is not acccesible i could t cover complete code coverage.
Please help me in writting a test case for below code.
const MyComponent = props => {
const [counterSecond, setCounterSecond] = React.useState(8);
const [counterFirst, setCounterFirst] = React.useState(0);
const handleIncrement = () => {
setCounterSecond(counterSecond + 1);
};
const handleDecrement = () => {
setCounterSecond(counterSecond - 1);
};
React.useEffect(() => {
if (counterSecond === 10) {
setCounterSecond(0);
setCounterFirst(1);
}
if (counterSecond === 3) {
setCounterSecond(1);
setCounterFirst(0);
}
if (counterSecond ===9) {
setCounterSecond(2);
setCounterFirst(1);
}
}, [counterSecond]);
return (
<div>
<div onClick={handleIncrement} >Increment</div>
<div onClick={handleDecrement} >Decrement</div>
</div>
);
};
export default MyComponent;
As you see the code is having useEffect, which looks after for the change in counterSecond value. But the internal conditions will only be covered when the state value matches 8 Or 3 Or 9.
Could you please guide me in writing Jest test case to cover the internal conditions in UserEffect.
1) And how to mock any state value
2) how to check of state value in Jest while using Hooks
Let's assume your component renders counterFirst and counterSecond otherwise their existence just doesn't make any sense. Something like
....
return (
<div>
<span test-id="counter">{`${counterFirst}:${counterSecond}`}</span>
<div onClick={handleIncrement} id="inc">Increment</div>
<div onClick={handleDecrement} id="dec">Decrement</div>
</div>
);
Then we would like to test our component. I strongly believe we don't need mock or assert against state or any internals. Instead we need to communicate through props and check render's result to check if component behaves as we expect.
So testing for initial state may look like:
function getCounter(wrapper) {
return wrapper.find("['test-id'='counter']").text();
}
it('renders 0:8 by default', () => {
const wrapper = mount(<MyComponent />);
expect(getCounter(wrapper)).toEqual('0:8');
});
But what to do with that code in useEffect? If you have enzyme version recent enough it should just work. I believe. If it does not - check what version you use.
And returning to testing. Up to your code sample counter should react on incremention and decremention in slightly untypical way. Say for inc: 0:8 -> 1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0(because for 0:9 and 1:3 there is appropriate logic in useEffect that causes re-render). So we will test that:
function doInc(wrapper) {
wrapper.find("inc").props().onClick();
}
it('jumps from 0:8 to 1:2 on inc', () => {
const wrapper = mount(<MyComponent />); // 0:8
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('1:2');
});
Actually here logic should create values cycled(1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0) so I would test that in single test case. But maybe in your real component it does not loop.
You may wonder how could you set up initial state for some particular case? The same way: by calling props to imitate clicks and other communication.
function doDec(wrapper) {
wrapper.find("dec").props().onClick();
}
it('increments from 0:5 to 0:6', () => {
const wrapper = mount(<MyComponent />); // 0:8
doDec(wrapper); // 0:7
doDec(wrapper); // 0:6
doDec(wrapper); // 0:5
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('0:6');
});
Maybe it's good idea to make some helper function.
But would it be faster to set state directly? Yes, it would be. But that also would make tests non-reliable. Say, your sample code never achieves '0:9'. And that may be an error rather a goal. And we expect testing helps us realize that. By setting state directly we would never know there is an issue.
I wanted to know if it was possible by combining webpack and js' oop to arrive at a functional code like the one presented below.
The goal is to be able to isolate each of the elements of my site (sidebar, main,...) in different files while making sure that they can interact between.
Is this possible with webpack and pure js or not?
import ApplePicker from "./my_path/applePicker.js";
import NiceFarmer from "./my_path/niceFarmer.js";
const orchard = function () {
const appleNumber = 10;
const jack = new ApplePicker();
const daniel = new NiceFarmer();
jack.eatAnApple();
daniel.eatAnApple();
// appleNumber have to be now === 2
}
// Example of applePicker.js structure
const ApplePicker = function () {
this.eatAnApple = function () {
// Do something
}
}
export default ApplePicker;
yes you can.
If you simply want to consume a variable from applePicker.js:
// applePicker.js
export const apples = 10
If you want to be able to reassign that variable you might want to add a simple facade layer on top of that:
// applePicker.js
let apple = 5
export function getApple() {
return apple;
}
export function setApple(newValue) {
apple = newValue;
}
Even better, if you want other functions to "fire" when a variable is changed, use the Observer pattern
While the official docs says,
While window is globally available in JavaScript, it causes testability problems, because it is a global variable. In AngularJS we always refer to it through the $window service, so it may be overridden, removed or mocked for testing.
I still cannot make sense of it. 😕 How can I benefit from $window in my unit tests code? In my snippet below, I can spy/mock and make use of the native window object, with or without $window. How does it cause testability problems?
angular.module('messagePopper', [])
.factory('popper', function popperFactory($window) {
return {
popupMessage(message) {
alert(message);
},
popupMessageWith$window(message) {
$window.alert(message);
}
};
});
describe('messagePopper: popper service', () => {
let $injector;
let $window;
let popper;
beforeEach(() => {
module('messagePopper');
inject((_$injector_) => {
$injector = _$injector_;
$window = $injector.get('$window');
popper = $injector.get('popper');
});
});
it('should popupMessage correctly', () => {
const message = 'welcome glenn#foodie.net';
const alertMock = spyOn(window, 'alert');
popper.popupMessage(message);
expect(alertMock)
.toHaveBeenCalledWith(message);
});
it('should popupMessageWith$window correctly', () => {
const message = 'welcome glenn#foodie.net';
const alertMock = spyOn($window, 'alert');
popper.popupMessageWith$window(message);
expect(alertMock)
.toHaveBeenCalledWith(message);
});
});
Fiddle here: https://jsfiddle.net/glenn/x42uex66.
While using the global window object works, there might be times where a test will fail, causing the windows object to not be cleaned up for the next test. In which case you would suddenly see a lot of tests failing for seemingly no reason, instead of just the one test that caused the issue.
I just upgraded my project's React version to 13.3 and setProps() is no longer working. I'm using it in this Mocha test and I'm not sure how to rewrite it now. What are my options?
it('reloads search results when props change ', function() {
var loadResultsSpy = sinon.spy(searchView, 'loadSearchResults');
var newProps = {searchBy: 'foo', searchTerm: 'bar'};
searchView.setProps(newProps);
expect(loadResultsSpy.calledWith(newProps.searchBy, newProps.searchTerm)).toBe(true);
});
In the most general case, React recommends just re-rending the top-level component, which essentially just updates the props if the new render is of the same component type. Since TestUtils.renderIntoDocument is simply a shortcut for creating a DOM node and doing a regular render into it, something like this will work (I'm making some assumptions about the setup of your tests):
var searchView, div;
beforeEach(function() {
var comp = <SearchView searchBy="baz" searchTerm="quix" />;
div = document.createElement('div');
searchView = React.render(comp, div);
});
it('reloads search results when props change', function() {
var loadResultsSpy = sinon.spy(searchView, 'loadSearchResults');
var comp = <SearchView searchBy="foo" searchTerm="bar" />;
React.render(comp, div);
expect(loadResultsSpy.calledWith("foo", "bar")).toBe(true);
});