I've been experimenting with GraphQL/Apollo in Typescript and run into a huge amount of really obvious typing issues that make me wonder whether I'm just doing it wrong.
Effectively, what I'd like to do (since it makes sense to me) is compose the data for my components by plastering in multiple HOC calls. Here's an example of what I mean (sans imports)
interface Props {
theme: Theme;
}
class Navigation extends React.Component<Props & ViewerProps & PageProps> {
render() {
const { viewer, page } = this.props;
return <h1>Hello, {viewer.name}; welcome to {page.name}</h1>;
}
}
export default withPage(withViewer(Navigation));
Elsewhere:
<Navigation theme={this.theme} />
Is this actually a pattern of any kind in Apollo? Are there any references out there which use this, or something similar?
Thanks
In Apollo 2.1 they upgraded to use render prop functions.
https://reactjs.org/docs/render-props.html which will help with stronger typing through the components.
https://dev-blog.apollodata.com/introducing-react-apollo-2-1-c837cc23d926
One thing I've been doing with components with HoCs is to cast the HoC with React.ComponentType so that it can make sure you're passing in the correct props to the component
const NavigationContainer: React.ComponentType<Props> =
withPage(withViewer(Navigation));
export default NavigationContainer;
Related
React doesn't provide an API that lets you pass in context to a created component class, so you have to write a wrapper component that provides the context.
Unfortunately, once you do this, you no longer have direct access to the component you are trying to test - unlike TestUtils.renderIntoDocument, functions like TestUtils.findRenderedComponentWithType don't return the actual rendered component instance, they only return the component constructor. Thus you can't call methods on the component, or set the component state to some known value before executing the test. The only thing you really have access to is the DOM node for your component, which is fine if all you want to do is black box testing, but for some kinds of components that's not sufficient.
I'm curious to know if anyone has come up with a solution for this. I've tried about a dozen different approaches, none of which work. (For example, I tried using 'ref' in my wrapper component, but it has the same problem - doesn't give you access to the real object.)
(Answering my own question)
Turns out the correct answer to all of this is to use enzyme, which replaces the standard React test utils - it offers a ton of features with a jQuery-like API, and best of all it completely supports component contexts. I've switched all of my tests over to it and it's great!
You can build a mock parent component like:
class MockContextContainer extends Component {
static propTypes = {
children: PropTypes.element.isRequired,
};
static childContextTypes = {
onSetTitle: PropTypes.func,
};
getChildContext() {
return {
onSetTitle: () => {},
};
}
render() {
return this.props.children;
}
}
Then use it in your test (in this case its a forgot password form example):
const cxtForgot = TestUtils.renderIntoDocument(
<MockContextContainer><ForgotPasswordForm /></MockContextContainer>
);
Which is what you may already be doing.
You can then do things like:
const input = TestUtils.findRenderedDOMComponentWithClass(
cxtForgot, 'ForgotPasswordForm-input'
);
// enter a valid email
input.value = 'abc#hotmail.com';
TestUtils.Simulate.change(input);
// no error class and button is now enabled
assert(!input.classList.contains('error'));
const button1 = TestUtils.findRenderedDOMComponentWithClass(
cxtForgot, 'primary-button'
);
assert(!button1.disabled);
the Simulate.change above can change the internal state of the component.
As for you question: "set the component state to some known value before executing the test", you can pass in different props to the component and have different tests for each scenario
I'm having trouble setting up tests for a component that relies on a redux store passed down from context...
My app has a root component that gives its children the redux store as context:
import ApplicationStore from './app-store.js'
class Root extends Component {
getChildContext() {
return { store: ApplicationStore }
}
render(){...}
}
Root.childContextTypes = {
store: PropTypes.object,
};
I have a component that depends on the store (passed down from context):
class List extends Component {
render(){
const items = this.context.store.getState();
return items.map((_, i) => (
<div key={i}>{_.name}</div>
));
}
}
List.contextTypes = {
store: PropTypes.object,
};
So my question is: How to I "inject" the store object into my component's context? Would I have to unmock(./app-store.js)? Additionally, how can I pre-fill the store with a couple fixtures?
Thanks!
I know this does not answer your question, but I would like to point you to the React.js documentation on contexts:
Most applications will never need to use context. Especially if you are just getting started with React, you likely do not want to use context. Using context will make your code harder to understand because it makes the data flow less clear. It is similar to using global variables to pass state through your application.
and
Do not use context to pass your model data through components. Threading your data through the tree explicitly is much easier to understand. Using context makes your components more coupled and less reusable, because they behave differently depending on where they're rendered.
If you use props to pass your store (or even only the required parts of it) to your child components, then your problem is already solved because in your test, you can simply inject your mocked or stubbed store.
In a component it is really easy to have an optional action provided to the component. In the JS of the component I can write:
if (this.get('someAction')) {
this.sendAction('someAction');
}
In my application route I have a 'generic action' that saves me providing widget components with long lists of actions, it looks like this:
genericAction: function(customActionName, customActionParams) {
this.send(customActionName, customActionParams);
}
For various reasons (including using genericAction in some components to fire an action a test could subscribe to, but the app not necessarily use in some hard to test async/pretender workflows) I would prefer to check the action exists, i.e:
genericAction: function(customActionName, customActionParams) {
if (this.get(customActionName)) {
this.send(customActionName, customActionParams);
}
}
Similar to how you can in a component, however this does not work, nor does this.controller.get(customActionName).
Other than keeping a hard coded list of actions, how can I achieve this?
If you keep your actions in the routes/application.js file itself then the code would be
In Ember 2.0 or later:
if(Em.get(this.actions, actionName)) {
this.send(actionName);
}
In Ember 1.13
this.actions is undefined in Ember 1.13, you have to use this._actions
if(Em.get(this._actions, actionName)) {
this.send(actionName);
}
If you need to support both Ember 1.x and 2.x then use something like:
let actions = this.actions || this._actions;
if(Em.get(actions, actionName)) {
this.send(actionName);
}
If you keep your actions in the application controller (controllers/application.js) then siva - abc's answer works great.
You can check for the actions in controller.actions. In your case, you have to check as
if(Em.get(this.controller.actions, actionName)) {
this.get('controller').send(actionName);
}
Here is a demo
if you are in a component you can use
if (this.get('yourActionName')) { }
In my ember application I want to have modules on different namespaces. I have an App Namespace and for each module there is an App.ModuleName namespace.
So far so good, I can access everything so far using App/ModuleName/SomeResource syntax. Now I have a controller that has a dependency on a controller in one of the module namespaces. I put up the controllers like this:
App.ModuleName.FooController = Ember.Controller.extend({
fooVal: 42
});
App.SomeController = Ember.Controller.extend({
needs: ['App/ModuleName/Foo', 'bar']
});
That seem to work so far telling by ember not complaining that the needed controller doesn't exist.
Now, how do I acces the controller in my handlebars template? For the bar controller its easy, just using controllers.bar.someProperty but I cannot access the App.ModuleName.FooController. I tried:
{{controllers.App/ModuleName/Foo.fooVal}}
{{controllers.App.ModuleName.Foo.fooVal}}
{{controllers.Foo.fooVal}}
and so on, every combination I could think of but it didn't work. Is it possible (and how) to get this running? Can someone please enlighten me?
And by the way: Even on the controllers I use needs successfully, if I debug them (logging them into the console, from my code directly or with a handlebars helper) the controllers property is always undefined. Is there a way to check the needed controller references?
Many thanks in advance.
To my knowledge, Ember's Container looks up stuff via the resolver. And it only looks for stuff on the application's namespace.
Some examples from the DefaultResolver docs.
'controller:post' //=> App.PostController
'controller:posts.index' //=> App.PostsIndexController
'controller:blog/post' //=> Blog.PostController
'controller:basic' //=> Ember.Controller
To achieve what you need you will need to provide a custom Resolver that looks up stuff in the different namespace when creating the Application.
App = Ember.Application.create({
resolver: MyNewResolver
});
For everyone who is interested in how I solved the issue and what I tried and learned:
I did some diggin in the code and tried a few things. I got the desired output using
a) A custom Handlebars helper that returns the property of the controller like this:
{{ myhelper 'App.ModuleName.FooController' 'fooVal'}}
with the following (quick and dirty) helper:
Ember.Handlebars.registerBoundHelper('myhelper', function(arg1, arg2, opts) {
if (opts && opts['data']) {
var ctrl = opts.data.properties[0];
var prop = opts.data.properties[1];
var controller = this.get('container').lookup('controller:' + ctrl.split('.').join('/'));
if (controller) {
return controller.get(prop);
}
}
});
The problem with this is, I couldn't get databinding to work, so if I changed my underlying model, the view didn't update.
b) Overriding the Controllers init() method to get the controller instance like this:
init: function() {
this.module = this.get('container').lookup('controller:App/Module/Foo');
}
and then in the template:
{{module.fooVal}}
In the second way, also Databinding worked, but It didn`t feel correct, so I did some googlin and came across this post on the emberjs issue list:
https://github.com/emberjs/ember.js/issues/683#issuecomment-5122333
As stated by tomdale, nested namespaces are not really something that is encouraged in ember, but multiple 'toplevel' namespaces are ok. So I decided to put up a toplevel namespace for every module and use a custom resolver to resolve them. Works like a charm now and feels like the right way to do it.
Any additional suggestions and comments about the pro's and con's of my second and final way of solving the problem would be much appreciated.
I've been reading Misko Hevery's classic articles about Dependency injection, and basically 'separating the object graph creation code from the code logic'.
The main idea seems to be "get rid of the 'new' operators", put them in dedicated objects ('Factories') and inject everything you depend on."
Now, I can't seem to wrap my head about how to make this works with objects that are composed of several other components, and whose job is to isolate those components to the outerworld.
Lame example
A View class to represent a combination of a few fields, and a button. All the components depend on a graphical ui context, but you want to hide it behind the interfaces of each sub-component.
So something like (in pseudo-code, language does not really matter I guess):
class CustomView() {
public CustomView(UIContext ui) {
this.ui = ui
}
public void start() {
this.field = new Field(this.ui);
this.button = new Button(this.ui, "ClickMe");
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// The interface of this component is that callers
// subscribe to "addValueEnteredListener"..)
public void addValueEnteredListener(Callback ...) {
}
public void fireValueEnteredListener(text) {
// Would call each listeners in turn
}
}
The callers would do something like :
// Assuming a UIContext comes from somewhere...
ui = // Wherever you get UI Context from ?
v = new CustomView(ui);
v.addValueEnteredListener(function (text) {
// whatever...
});
Now, this code has three 'new' operators, and I'm not sure which one Misko (and other DI proponents) are advocating to rid off, or how.
Getting rid of new Field() and new Button()
Just Inject it
I don't think the idea here is to actually inject the instances of Field and Button , which could be done this way :
class CustomView() {
public CustomView(Field field, Button button) {
this.field = field;
this.button = button;
}
public void start() {
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// ... etc ...
This makes the code of the component lighter, surely, and it actually hides the notion of UI, so the MetaForm component has clearly been improved in terms of readability and testability.
However, the burden is now on the client to create those things :
// Assuming a UIContext comes from somewhere...
ui = // wherever ui gets injected from
form = new Form(ui);
button = new Button(ui);
v = new CustomView(form, button);
v.addValueEnteredListener(function (text) {
// whatever...
});
That sounds really troubling to me, espacially since the client know has to all the inners of the class, which sounds silly.
Mama knows, inject her instead
What the articles seems to advocate is instead injecting a Factory to create the components elements.
class CustomView() {
public CustomView(Factory factory) {
this.factory = factory;
}
public void start() {
this.field = factory.createField();
this.button = factory.createButton();
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// ... etc ...
And then everything gets nice for the caller, because its just has to get the factory from somewhere (and this factory will be the only to know about the UI context, so hurray for decoupling.)
// Assuming a UIContext comes from somewhere...
factory = // wherever factory gets injected from
v = new CustomView(factory);
v.addValueEnteredListener(function (text) {
// whatever...
});
A possible drawback is that when testing the MetaForm, you will typically have to use a 'Mock' Factory that ... create Mocks version of the Field & Button classes. But obviously there is another drawback ...
Yo' Factory so fat!!
How big will the Factory get ? If you follow the pattern rigorously, then every single frigging component you ever want to create in you application at runtime (wich is typically the case for UI, right) will have to get its own createXXXXX methods in at least one factory.
Because now you need :
Factory.createField to create the field
Factory.createButton to create the button
Factory.createMetaForm to create the field, the button and the MetaForm when a client (say the MetaEditPage wants to use one)
And obviously a Factory.createMetaEditPage for the client..
... and its turtles all the way.
I can see some strategies to simplify this :
As much as possible, separate the parts of the graph that are created at "startup" time from the parts that are created at runtime (using an DI framework like Spring for the former, and factories for the latter)
Layer the factories, or collocate related objects in the same factories (a UIWidgetFactory would make sense for Field and Button, but where would you put the other ones ? In a Factory linked to the Application ? To some other logical level ?)
I can almost hear all the jokes from C guys that no Java app can do anything without calling a ApplicationProcessFactoryCreator.createFactory().createProcess().startApplication() chain of nonsense...
So my questions are :
I am completely missing a point here ?
If not, which strategy would you suggest to make the things bearable ?
Addendum : why I'm not sure dependency injection would help
Assume I decide to use dependency injection, with a guice-like framework. I would end up writing code like this :
class CustomView
#Inject
private Field fiedl;
#Inject
private Button button;
public void start() {
this.button.addEventListener(....
// etc...
And then what ?
How would my "Composition Root" make use of that ? I can certainely not configure a "singleton" (with a lowercase 's', as in 'the single instance of a class) for the Field and the Button (since I want to create as many instances of them as instances of MetaForm ?
It would not make sense to use a Provider, since my problem is not which instance of buttons I want to create, but just that I want to create it lately, with some configuration (for example its text) that only makes sense for this form.
To me DI is not going to help because I am new-ing parts of my component rather than Dependencies. And I suppose I could turn any subcomponent into a dependency, and let a framework inject them. It's just that injecting subcomponents looks really artificial and couter-intuitive to me, in this case... so again, I must be missing something ;)
Edit
In particular, my issue is that I can't seem to understand how you would test the following scenario :
"when I click on the button, if the Field is empty, there should be an error".
This is doable if I inject the button, so that I can call its "fireClicked" event manually - but it feels a bit silly.
The alternative is to just do view.getButton().fireClicked() , but that looks a bit ugly...
Well, you can use some DI Framework (Spring or Guice) and get rid of factory method completely. Just put some annotation on the field/constructor/set method and DI Framework will do the work. At unit-test use mock framework.
How about not being overly obsessed with the "no new" dogma ?
My take is that DI works well for - well you know, Dependencies, or Delegates. Your example is about composition and IMHO it absolutely makes sense that the owning entity (your CustomView) creates explicitly its components. After all, the clients of the composite do not even have to know that these components exist, how they are initialized or how you use them.