How do you test complex parent child communications using testing library - unit-testing

I would like to understand how to test a parent component that depends on the complex logic in one child and updates another one.
Let's imagine we have a huge form (parent) on a page and we want to have the ability to update it.
When there is at least one change we should show a confirmation bar (a child) to apply the change.
To amend the form data we have an option to click on a button to open a modal component (a child) with a form group inside. Moreover, the modal makes an API call to fetch some data and uses a timeout to apply new changes.
What would you test in the case?
P.S. It's easy to test each child component separately but when you try to write a functional test for the parent component then you may notice that the test is complex and unmaintainable due to async login in children

Related

Set focus on component after modal close

I would like to know what is recommended way to focus on component from outside the component. I am trying to focus on a input field when the person closes the modal window.
Typically you would use an action in the modal that triggers when the close button is clicked, and you would send the action up to the component with the input with sendAction. In the component with the input, you could then use Ember.$ or any other method to tell the browser to focus on an element.
The situation is more complex if the modal is not inside the component that contains the input. In that case you might need to use a service or event. But it's much easier to use the first method.

Ember: Call a component action from a controller

I have a component working pretty well and now I need to call it inside a controller.
Scenario: I have an ember application, and I have an update button controller, I did a component that just display a toast(Materializecss) with some message I pass as parameter to the component and both the button and the toast are working well separately. I need to call inside the button controller this component to display to the user if the update was successfully or not using this component I did. Any sugestion of how can I call this component inside the controller? Thanks
have a look at the ember-twiddle I created and see if it fits the bill, in regards to what you want to do ?
You should instead of thinking "calling the component", rather, how can I push updated attributes/data to the component.
Ember relies on the "Data Dow Actions Up" pattern. This implies that you cannot make an explicit call to a component action from a controller. (see https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up for example)
Instead, a better design should be to define a service to manage data : messages to be "toasted". Then make this service available by injecting in in your controller. You will be able to call methods to register a new messages and generate new data.
Provide also a component template (to be included in your own templates) that will be in charge to display the new message, etc. Each change in the data managed by the service will lead to a component template update.
You should definitely take a look to https://www.npmjs.com/package/ember-toastr

Ember communicate between child components

I'm trying to make a header component, which has several inside components,
such as a button, and one of them opens a side menu that is a child component also.
How can target an action of one child component to another child component?
In this case, target the open action in the button component to the overlay component?
{{#header-block class="main-nav"}}
{{button-icon icon="fi-torso" class="nav-action left" openMenu=(action "open" target=) }}
{{#overlay-block}}
{{#side-menu}}
<p>side menu one</p>
{{/side-menu}}
{{/overlay-block}}
{{/header-block}}
You can't, at least not using the public API. You may have read this before, but Ember's components follow the "data down, actions up" approach. In order to do what you want, you have to send an action from the button component to your controller, mutate some data based on that action, then pass that data into the overlay component. There can be no direct communication between the two components.

Should this be in model or view?

I am using QFileSystemModel to populate my tree view. User can right click on a tree node (a folder) and perform an operation (exports all certain data files under this folder).
I have this export under the on_tree_clicked() but I feel like this operation belongs to model.
Will it be better if I derive my own QFileSystemModelWithExportfrom QFileSystemModeland added the export function? From on_tree_clicked(), I then just call it?
Is there another way to do this nicely? I want my on_tree_clicked() to be shorter and cleaner.
Also I am quite new to Qt, how do we derive from Qt core class like QFileSystemModel? When I am adding class, it lets me derive from QObject, QWidget etc but not from any model class.
Your UI should only deal with UI problems. i.e. button presses, user interaction.
This should then send it through to your model which actually executes the code.
Think of it this way, if your export to file takes, lets say 5 seconds, that's 5 seconds you can't use your UI for because that thread is doing the write to file. IF you have this model you have the opportunity to multi thread that particular event and keep your UI responsive whilst performing actions.
Code wise:
onTreeClicked() can be fairly short. It could perform the following:
myModel->writeDataFromNodeToFile();
& then inside that function you can have all the functionality you need to write to file. Open/Close/stream data etc

How to make an action affect a sibling view without controller.get('view')?

Quick context:
Application view has 2 outlets. One for a toolbar. The other for the routable "main" view hierarchy.
app -- main
\-- toolbar
I need some buttons in the toolbar to trigger events in the "main" view. Not update any data in any model. I simply instruct it to trigger some changes to a drawing library that the view is presenting. Clearing the canvas, resetting zoom value and such.
In 1.0 pre2 and earlier I have used actions and router.get('someController.view') to get access to the view I want and trigger the action/method/event. Hardly the pinnacle of application design but it worked fine.
This option is now gone and I am at a loss for a good alternative. What mechanism should I use when communicating between views that are not in a child/parent hierarchy? Everything I have come up with is clunky and triggers my sense that "Ember has a better way".
In short I want:
A toolbar-button to trigger an event
The main view to react to this and perform some updates on parts of itself.
The main view to NOT re-render in the Ember sense of the word as would through routing. It uses a drawing library and integrating all it's properties and behavior into Ember models and controllers would not be a lot of fun.
The toolbar and the main view share a parent view but are on different "branches".
Poor Options I am considering:
The toolbar is very much an application level concern but it does have some buttons that need to instruct specific views. One option I see within Ember is to nest the toolbar under the "main" view. This seems wrong for some of it's other functions.
Communication could be handled by a controller (and possibly even a model) that would hold properties that the toolbar sets and the "listening" view reacts to and resets the value of. This sounds like abuse of the controller and model purposes and like a pretty poor event listener setup.
I could make the drawing library an application global as App.Drawing or something but that does also seems bad. It would also mean that the actions still would not be able to make use of any data in the view to update the drawing library with.
Any suggestions?
What mechanism should I use when communicating between views that are not in a child/parent hierarchy?
In a typical ember application this communication should happen between controllers. Otherwise "Poor Option 2" is on the right track:
Communication could be handled by a controller (and possibly even a model) that would hold properties that the toolbar sets and the "listening" view reacts to and resets the value of.
Consider using two controllers. Toolbar actions will target the ToolbarController, which is responsible for maintaining the toolbar's state and for changing main in response to user action. ToolbarController should declare a dependency on MainController via the needs property. For example:
App.ToolbarController = Ember.Controller.extend({
needs: ['main'],
buttonOneGotAllPressed: function() {
main = this.get('controllers.main');
main.turnOffAnOption();
main.makeSomeOtherChange();
}
});
Now MainController can be focused on the state of MainView. It should not be aware of ToolbarController or it's buttons.
This sounds like abuse of the controller and model purposes and like a pretty poor event listener setup.
Agreed it would likely be an abuse of model purposes but it is exactly what controllers are for.
This is definitely not an event-listener setup, but that does not seem a good fit in your case. The toolbar you describe seems to exist only to interact with the main view, so it makes sense to have a toolbar controller that depends on main and interacts with it directly.
If the components are truly decoupled then an observer (Pub/Sub) pattern might be more appropriate. See How to fire an event to Ember from another framework if that's of interest.