coming from rspec, i am having trouble understanding mocking with jest. the approach i am trying for, is to automock a class's constructor and all of it's functions, and then unmock them one by one to test only that one function. the only documentation i can find on it, is with using 2 classes, mocking 1 class, and then testing that those functions are called from the other unmocked class.
below is a basic, contrived idea of what i am trying to do. can someone direct me to the jest-way of doing this?
foo.js
class Foo
constructor: ->
this.bar()
this.baz()
bar: ->
return 'bar'
baz: ->
return 'baz'
foo_test.js
// require the class
Foo = require('foo')
// mock entire Foo class methods
jest.mock('foo')
// unmock just the bar method
jest.unmock(Foo::bar)
// or by
Foo::bar.mockRestore()
// and should now be able to call
foo = new Foo
foo.bar() // 'bar'
foo.baz() // undefined (still mocked)
// i even tried unmocking the instance
foo = new Foo
jest.unmock(foo.bar)
foo.bar.mockRestore()
mockFn.mockRestore() worked for me with jest#24.9.0:
// Create a spy with a mock
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => {})
// Run test or whatever code which uses console.info
console.info('This bypasses the real console.info')
// Restore original console.info
consoleInfoSpy.mockRestore()
This does not strictly apply to the OP, but answer-seekers may end up here. You can mock a module except certain parts for all tests like so.
mocks/saladMaker.js
// Let Jest create the mock.
const saladMaker = jest.genMockFromModule('../saladMaker');
// Get the unmocked chop method.
const {chop} = jest.requireActual('../saladMaker');
// Patch it in.
saladMaker.chop = chop;
module.exports = saladMaker;
The key part is to use requireActual to get at the unmocked module.
bypassing module mocks
It is not possible to get the original module after mocking it in Jest. What jest.mock does is to replace the module with your mock.
So even you write:
Foo = require('foo')
jest.mock('foo')
Jest will hoist the jest.mock('foo') call on top of the call stack, so it's the first thing that happens when the test starts. This will also affect all other modules you import and that import foo.js.
You could try to use spyOn to spy on functions of an object, should work with classes as well, but I'm not quite sure.
I have tried a lot of things, but what eventually worked for me is (using Create React App):
setupTests.ts
jest.mock("./services/translations/translationsService", () => ({
__esModule: true,
default: {
initDict: (): void => undefined,
translate: (key: Phrases): string => key,
},
t: (key: Phrases): string => key,
}));
Which mocks the module for all tests. In order to unmock for a single test suite, I did:
jest.mock("../../../services/translations/translationsService", () =>
jest.requireActual("../../../services/translations/translationsService")
);
describe(() => { /* test suite goes here and uses real implementation */ });
For Jest#27.4.7
const mockChildComponent = jest.mock('../../../src/components/common/childComponent', () => ({
__esModule: true,
default: (props: Prop) => (
<div data-test-id="stub-chart-panel">
{props.label}
</div>
),
}));
test('mock child', async () => {
const wrapper = mount(
<ParentComponent />
);
expect(....);
});
mockChildComponent.restoreAllMocks();
test('default child component ', async () => {
const wrapper = mount(
<ParentComponent />
);
expect(....);
});
Related
I understand users may downvote my question, but I need to be sure, and I have no way of being sure, unless I ask react redux experienced person. Please answer and not downvote. question is it ok to refactor the code as shown below, or there may arise some issue
const mapStateToProps = (state) => {
const {
router,
classDetail,
categories,
instructorFreeSlots
} = state;
return {
router,
classDetail,
categories,
instructorFreeSlots
};
};
const mapStateToProps = (state) => ({
state.router,
state.classDetail,
state.categories,
state.instructorFreeSlots,
})
common code is:
const mapDispatchToProps = dispatch => ({
dispatch,
});
export default connect(mapStateToProps, mapDispatchToProps)(ClassDetailContainer);
First of all your refactoring improvements are not related to any data mutations. Let's review them:
1. mapStateToProps refactoring:
Your mapStateToProps refactoring regarding to Object Initializer and Shorthand property naming and it's syntactically incorrect. It can be:
const mapStateToProps = ({ router, classDetail, categories, instructorFreeSlots }) => ({
router, classDetail, categories, instructorFreeSlots
})
Also your first version is perfectly fine too. Here we mainly talk about syntactic sugar, so we shouldn't be worried to much. Choose your convention and stick with it.
2. mapDispatchToProps refactoring:
According to your use-case (where nothing is added to), you can omit passing the mapDispatchToProps function to the connect function and the dispatch function will be passed automatically to your ClassDetailContainer:
export default connect(mapStateToProps)(ClassDetailContainer)
Keep in mind that if you pass down mapDispatchToProps to the connect, mapDispatchToProps can be an Object or a Function.
Please check mapDispatchToProps official documentation for better understanding how it works, but here is the main idea:
If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with
every action creator wrapped into a dispatch call so they may be
invoked directly, will be merged into the component’s props.
If a function is passed, it will be given dispatch as the first parameter. It’s up to you to return an object that somehow uses
dispatch to bind action creators in your own way. (Tip: you may use
the bindActionCreators() helper from Redux.)
I would like to be able to alias a very generic function and specify part of the generic parameters, thus creating a less generic version of the same function. Something like the following:
function veryGeneric<X, Y>(someParam: Y): { result: X } {
// ...
}
type LessGeneric = typeof veryGeneric<X, string>
const lessGeneric: LessGeneric = veryGeneric
Where I would want the lessGeneric function to essentially be typed as:
function lessGeneric<X>(someParam: string): { result: X } {
// ...
}
Is this possible in any way?
I know I could create a wrapper function, but I would prefer to not have to specify the parameter typings again (and not having to pay the overhead of another function call, even if it’s tiny, would be a bonus).
Here’s the real example I’m dealing with. Given a function declaration (from react-tracking) like the following:
declare function track<T = {}, P = {}>(trackingInfo?: TrackingInfo<T, P>, options?: Options<Partial<T>>): Decorator
I want to be able to define an alias that specifies the trackingInfo parameter’s typing but leaves P generic. i.e. I want an alias that’s essentially typed as:
interface ValidAnalyticsEntries {
page: string
action: string
}
declare function trackSpecificToOurAnalyticsSchema<P = {}>(trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>, options?: Options<Partial<ValidAnalyticsEntries>>): Decorator
To define generic type alias you can define an interface describing your function signature:
interface VeryGeneric<X, Y> {
(someParam: Y): { result: X };
}
type Foo = { foo: number };
type LessGeneric<X = Foo> = VeryGeneric<X, string>;
const lessGeneric: LessGeneric = veryGeneric;
You can do this:
const lessGeneric: <X>(someParam: string) => { result: X } = veryGeneric;
I'm just spelling out the desired type of lessGeneric without trying to force TypeScript to convert the type of veryGeneric to the type of lessGeneric first. There's no wrapper function, though.
Does this work for you? If not, please add more detail to your use case and example. Specifically, the X parameter is almost impossible to implement (how can the implementation get its hands on a value of type X) and the Y parameter is doing next to nothing (the someParam argument is of type Y, but nothing else is using Y, so you might as well just declare someParam to be of type any and not use Y).
Hope that helps; good luck!
EDIT: My suggestion for the real example looks like:
const trackSpecificToOurAnalyticsSchema: <P = {}>(
trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>,
options?: Options<Partial<ValidAnalyticsEntries>>)
=> Decorator = track;
Or, abstracting away from ValidAnalyticsEntries:
type PartiallySpecifiedTrack<T = {}> = <P = {}>(
trackingInfo?: TrackingInfo<T, P>,
options?: Options<Partial<T>>)
=> Decorator
const trackSpecificToOurAnalyticsSchema:
PartiallySpecifiedTrack<ValidAnalyticsEntries> = track;
Note that in all these cases you still have to write out function signature at least two times in total: once when you define the fully generic track(), and once to define PartiallySpecifiedTrack. But you can re-use PartiallySpecifiedTrack with different values for T if you want:
const anotherTrack: PartiallySpecifiedTrack<{ foo: string }> = track;
declare const trackingInfo: TrackingInfo<{ foo: string }, {bar: number}>
anotherTrack(trackingInfo); // okay
Okay, that's the best I can do. Good luck!
I found the following example in the Function.name documentation
const o = {
foo(){}
};
o.foo.name; // "foo";
The problem in typescript (typed here):
const o: { foo: () => void } = {
foo: () => {
}
};
o.foo.name;
comes when I want to retrieve
o.foo.name, where I will get an error
TS2339 (property "name" does not exist)
How can I deal with it, keeping the object typing?
I want to avoid having to cast the property "foo" like (<any>o.foo).name
PS: The use case is to keep the typing for further refactoring. For instance the following is safe to be refactored:
spyOn(o, (<any>o.foo).name)
While this one is not
spyOn(o, "foo")
PS 2: It seems retrieving function name could be problematic on ts: Get name of function in typescript
The problem is that this code only works for newer versions of Javascript. If you change the target on the typescript compiler settings to es2015 the problem goes away. If you target es5 the definitions for that version do not include the name property because it might not work on older Javascript runtimes.
If you are ok with targeting es2015, that is ok, if not you should come up with a different solution that works for es5.
If you are targeting an environment that supports this property but you don't yet trust the es2015 implementation for all features, you could just add the the Function interface the missing property. At the top level in one of your files you can redefine the Function interface, and this will be merged into the default definition, adding the extra property:
interface Function {
/**
* Returns the name of the function. Function names are read-only and can not be changed.
*/
readonly name: string;
}
Post ES2015, this:
const o: { foo: () => void } = {
foo: () => { }
};
console.log(o.foo.name);
should work just fine.
Check it in the Typescript Playground, and observe the produced JavaScript. You will see the common sections with the foo example you mentioned.
Here is the console, nice and clean:
Pre-ES2015, this wouldn't work and I think you would have to cast it, if targeting post-ES2015 is not an option.
I'm sure something like this has been asked before, but I've read several forums and have not come to a solution. I am using PHPUnit version 3.7.38, if that makes any difference.
I'm in PHPUnit testing a function.
public function someFunction()
{
$variable2 = Input::get('someValue');
if (strlen($variable2) == 0) {
return Redirect::to('/somepage')->with(
'notification',
array(
'type' => 'danger',
'text' => 'text.'
)
);
}
...More Code that needs to be tested
My problem is that everytime PHPUnit runs, $variable2 returns null because it can't get someValue. The code the returns and skips the rest of the function. I want to somehow skip over $variable2's declaration and assign it to a value that has a strlen() greater than zero, so the test covers the rest of the function. Is there a way to do this?
I have read the documentation on PHPUnit's site about ignoring codeblocks, but have not had any luck with that. Maybe I'm not implementing the
/**
* #codeCoverageIgnore
*/
properly or maybe that's not even what codeCoverageIgnore is meant for. I tried putting the #codeCoverage in the actual code I'm testing, but I don't think that would be right either seeing how I still want to test the if branch if it is true. I wouldn't think you would have to edit the code being tested in order to test it either.
#CodeCoverageIgnore
This is used to tell the code coverage calculations to skip the this section and not include it in the calculation of test coverage. Therefore, this module would not be included in the counts for covered/uncovered lines of the test.
However, you really want to handle the Input:: method and set it. The best way to do this is to refactor your code, to move the Input rountine out, to be supplied by dependency injection, which would then allow you to Mock the Input routine to set your text string, and allow your test to continue.
class ToTest
{
private $InputObject
public function __construct($Input = NULL)
{
if(! is_null($Input) )
{
if($Input instanceof Input) // The class that you were referencing Input::
{
$this->SetInput($Input);
}
}
}
public function SetInput(Input $Input)
{
$this->InputObject = $Input
}
public function someFunction()
{
$variable2 = $this->InputObject::get('someValue');
if (strlen($variable2) == 0) {
return Redirect::to('/somepage')->with(
'notification',
array(
'type' => 'danger',
'text' => 'text.'
)
);
}
...More Code that needs to be tested
}
}
Test:
class InputTest extends PHPUnit_Framework_TestCase
{
// Simple test for someFunctione to work Properly
// Could also use dataProvider to send different returnValues, and then check with Asserts.
public function testSomeFunction()
{
// Create a mock for the Your Input class,
// only mock the someFunction() method.
$MockInput = $this->getMock('YourInput', array('someFunction'));
// Set up the expectation for the someFunction() method
$MockInput->expects($this->any())
->method('get')
->will($this->returnValue('Test String'));
// Create Test Object - Pass our Mock as the Input
$TestClass = new ToTest($MockInput);
// Or
// $TestClass = new ToTest();
// $TestClass->SetInput($MockInput);
// Test someFunction
$this->assertEquals('Test String', $TestClass->someFunction());
}
}
containerBuilder
.Register<IGraphClient>(context =>
{
var graphClient = new GraphClient(new Uri("http://localhost:9999/db/data"));
graphClient.Connect(); // Particularly this line
return graphClient;
})
.SingleInstance();
While I can figure out how to register interfaces to concrete classes, this particular class needs to be a single instance (I'm pretty sure this is LifeStyle.Singleton) and also call the graphClient.Connect() method. That's the main part I'm stuck on.
Based on JeffN825's answer I did this:
container.Register(
Component.For(
typeof (IGraphClient))
.ImplementedBy(typeof (GraphClient))
.LifeStyle.Singleton.UsingFactoryMethod(() =>
{
var graphClient = new GraphClient(new Uri("http://localhost:7474/db/data"));
graphClient.Connect();
return graphClient;
}));
You can use the ComponentRegistration<T>.UsingFactoryMethod<T> method which takes a delegate (Func) if you want to control the instance creation yourself (which would also give you the chance to call Connect).