How to prevent onChange event fire onBlur in Semantic-ui-react - semantic-ui-react

I expect onChange event fire when I select an Item in Dropdown component. However, onChange event fires even if I click elsewhere. How to prevent onChange event fire onBlur?
handleDomainChange = (e, data) => {
this.setState({
currantDomain_id: data.value,
currantWidget_id: "null",
}, () => {
this.props.dispatch(
statsFetch(
this.props.viewRange,
this.state.currantDomain_id,
this.state.currantWidget_id
)
);
this.widgetsDropdownOptions();
});
}
const DropdownDomains = () => (
<Dropdown
placeholder='all domains'
className="dropdown-title"
value={this.state.currantDomain_id}
selection
options={this.domainsDropdownOptions()}
onChange={this.handleDomainChange}
onBlur={this.nothing}
/>
)

Try <Dropdown selectOnBlur={false} .../>.

Related

How to check if conditional rendering is shown after selecting an option from a select list with React Testing Library?

I'm trying to test my component that has the following conditional rendering:
const MyComponent = () => {
const [isVisible, setIsVisible] = (false);
if(selectedOption == 'optionOne')
setIsVisible(true);
else
setIsVisible(false);
return (
<div>
<Select data-testid="select1" selectedOption={selectedOption} />
{isVisible ? <Select data-testid="select2" selectedOption={anotherSelectedOption} /> : null }
</div>
)}
If selectedOption in select1 is 'optionOne', then select2 shows up.
Here is how I am testing it:
describe('Testing', () => {
let container: ElementWrapper<HTMLElement>;
const testState = {
userChoice1: {
selectedOption: ['optionOne'],
},
userChoice2: {
selectedOption: ['test1', 'test2'],
},
} as AppState;
beforeEach(() => {
container = render(<MyComponent/>, testState);
});
it('should show select2 if optionOne is selected', async () => {
const { getByTestId, getAllByTestId } = render(<MyComponent/>);
expect(container.find('span').getElement().textContent).toBe("optionOne"); // this successfully finds select1 with optionOne selected, all good
await screen.findAllByTestId('select2')
expect(screen.getAllByTestId('select2')).toBeInTheDocument();
});
In the testing above, as select1 has optionOne selected, I expect to select2 to show up. However, I am getting an error Unable to find an element by: [data-testid="select2"]. It also returns the whole HTML body, where I see select1 element with optionOne selected, but no select2 at all as it seems to still be hidden.
What am I missing here? How can I unhide select2 within the unit test?

how to write unit testing for modal or alert popup in ionic 4

I want to cover unit testing for alert controller popup and callback handler in ionic 4?
it('should open popup', () => {
component.showAlertPopup();
const popupElem = fixture.debugElement.queryAll(By.css('alert-inner-button'));
console.log('popup element', popupElem);
});
async showAlertPopup() {
const alertOpts: AlertOptions = {
message: 'applied successfully',
button: [{
text: 'YES',
handler: () => {
this.router.navigateByUrl('app/home');
}
}]
};
const alert = await this.alertCtrl.create(alertOpts);
console.log('alert', alert);
alert.present();
}
I expected the popup element but it is undefined.

jest unit test to mock events

I have a utility file that determines the enter key-down and triggers the click event of all the button type submit present in the document.
I need help to simulate key-down of enter key, and mock buttons with type submit so as to trigger their click.
I am using jest and enzyme for testing .
Below is the utility code :
const runSubmitEventListener = () => {
document.onkeydown = (e) => {
e = e || window.event;
if(e.key && e.key.toLowerCase() === 'enter'){
document.querySelector('button[type="submit"]') && document.querySelectorAll('button[type="submit"]').click();
}
}
}
export default{
runSubmitEventListener
}
Also, have started writing the test cases for which below is the file. Please suggest further steps, as I am new to jest unit testing.
import events from './events';
describe('events utility', () => {
it('should have runSubmitEventListener to be defined', () => {
expect(events.runSubmitEventListener).toBeDefined();
});
it('should trigger click of button type submit on keydown enter key', () => {
const event = new keyBoardEvent('keydown', {'key': 'enter', 'keycode': 13});
document.dispatchEvent(event);
// expect(events.runSubmitEventListener).toHaveBeenCalled();
});
});

React Semantic UI - Modal without trigger?

Is it possible to use a Modal without a trigger? I will open and close it via state.
For example, I want to use onClick on an input field(with a file name) to open the modal with a file chooser and then edit the name of the choosen file in the input field. All this in a nested modal...
Looks much simpler if I will have both modals in a parent component without the triggers, and I will display/hide them via open={true/false}
Thanks
Yes it is. Don't set the prop trigger (it is not required) and just provide the open value from state/props.
class container extends Component {
state = {
isParentOpen: false,
isChildOpen: false
}
handleClick = () => {
this.setState({
isParentOpen: !this.state.isOpen
});
}
handleFocus = () => {
this.setState({
isChildOpen: true
});
}
render() {
return (
<div>
<Modal
open={this.state.isParentOpen}
size="large"
>
...
<Input onFocus={this.handleFocus} />
</Modal>
<Modal
open={this.state.isChildOpen}
size="small"
>
...
</Modal>
<Button onClick={this.handleClick} />
</div>
);
}
}
(You can nest Modal if you want to)
Pass a prop to the modal component and fire handleOpen according to the prop on ComponentDidMount. This will allow the modal to be closed.
class ModalContainer extends Component {
componentDidMount() {
const { startOpen } = this.props;
if (startOpen) {
this.handleOpen();
}
}
handleOpen = () => this.setState({ modalOpen: true });
handleClose = () => this.setState({ modalOpen: false });
render() {
return (
<Modal open={this.state.modalOpen} onClose={this.handleClose} />
)
}

Mocking $modal in AngularJS unit tests

I'm writing a unit test for a controller that fires up a $modal and uses the promise returned to execute some logic. I can test the parent controller that fires the $modal, but I can't for the life of me figure out how to mock a successful promise.
I've tried a number of ways, including using $q and $scope.$apply() to force the resolution of the promise. However, the closest I've gotten is putting together something similar to the last answer in this SO post;
I've seen this asked a few times with the "old" $dialog modal.
I can't find much on how to do it with the "new" $dialog modal.
Some pointers would be tres appreciated.
To illustrate the problem I'm using the example provided in the UI Bootstrap docs, with some minor edits.
Controllers (Main and Modal)
'use strict';
angular.module('angularUiModalApp')
.controller('MainCtrl', function($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function() {
$scope.modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function() {
return $scope.items;
}
}
});
$scope.modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
})
.controller('ModalInstanceCtrl', function($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function() {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
});
The view (main.html)
<div ng-controller="MainCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>I is a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn btn-default" ng-click="open()">Open me!</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
The test
'use strict';
describe('Controller: MainCtrl', function() {
// load the controller's module
beforeEach(module('angularUiModalApp'));
var MainCtrl,
scope;
var fakeModal = {
open: function() {
return {
result: {
then: function(callback) {
callback("item1");
}
}
};
}
};
beforeEach(inject(function($modal) {
spyOn($modal, 'open').andReturn(fakeModal);
}));
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope, _$modal_) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$modal: _$modal_
});
}));
it('should show success when modal login returns success response', function() {
expect(scope.items).toEqual(['item1', 'item2', 'item3']);
// Mock out the modal closing, resolving with a selected item, say 1
scope.open(); // Open the modal
scope.modalInstance.close('item1');
expect(scope.selected).toEqual('item1');
// No dice (scope.selected) is not defined according to Jasmine.
});
});
When you spy on the $modal.open function in the beforeEach,
spyOn($modal, 'open').andReturn(fakeModal);
or
spyOn($modal, 'open').and.returnValue(fakeModal); //For Jasmine 2.0+
you need to return a mock of what $modal.open normally returns, not a mock of $modal, which doesn’t include an open function as you laid out in your fakeModal mock. The fake modal must have a result object that contains a then function to store the callbacks (to be called when the OK or Cancel buttons are clicked on). It also needs a close function (simulating an OK button click on the modal) and a dismiss function (simulating a Cancel button click on the modal). The close and dismiss functions call the necessary call back functions when called.
Change the fakeModal to the following and the unit test will pass:
var fakeModal = {
result: {
then: function(confirmCallback, cancelCallback) {
//Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
}
},
close: function( item ) {
//The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
this.result.confirmCallBack( item );
},
dismiss: function( type ) {
//The user clicked cancel on the modal dialog, call the stored cancel callback
this.result.cancelCallback( type );
}
};
Additionally, you can test the cancel dialog case by adding a property to test in the cancel handler, in this case $scope.canceled:
$scope.modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$scope.canceled = true; //Mark the modal as canceled
$log.info('Modal dismissed at: ' + new Date());
});
Once the cancel flag is set, the unit test will look something like this:
it("should cancel the dialog when dismiss is called, and $scope.canceled should be true", function () {
expect( scope.canceled ).toBeUndefined();
scope.open(); // Open the modal
scope.modalInstance.dismiss( "cancel" ); //Call dismiss (simulating clicking the cancel button on the modal)
expect( scope.canceled ).toBe( true );
});
To add to Brant's answer, here is a slightly improved mock that will let you handle some other scenarios.
var fakeModal = {
result: {
then: function (confirmCallback, cancelCallback) {
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
return this;
},
catch: function (cancelCallback) {
this.cancelCallback = cancelCallback;
return this;
},
finally: function (finallyCallback) {
this.finallyCallback = finallyCallback;
return this;
}
},
close: function (item) {
this.result.confirmCallBack(item);
},
dismiss: function (item) {
this.result.cancelCallback(item);
},
finally: function () {
this.result.finallyCallback();
}
};
This will allow the mock to handle situations where...
You use the modal with the .then(), .catch() and .finally() handler style instead passing 2 functions (successCallback, errorCallback) to a .then(), for example:
modalInstance
.result
.then(function () {
// close hander
})
.catch(function () {
// dismiss handler
})
.finally(function () {
// finally handler
});
Since modals use promises you should definitely use $q for such things.
Code becomes:
function FakeModal(){
this.resultDeferred = $q.defer();
this.result = this.resultDeferred.promise;
}
FakeModal.prototype.open = function(options){ return this; };
FakeModal.prototype.close = function (item) {
this.resultDeferred.resolve(item);
$rootScope.$apply(); // Propagate promise resolution to 'then' functions using $apply().
};
FakeModal.prototype.dismiss = function (item) {
this.resultDeferred.reject(item);
$rootScope.$apply(); // Propagate promise resolution to 'then' functions using $apply().
};
// ....
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
fakeModal = new FakeModal();
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$modal: fakeModal
});
}));
// ....
it("should cancel the dialog when dismiss is called, and $scope.canceled should be true", function () {
expect( scope.canceled ).toBeUndefined();
fakeModal.dismiss( "cancel" ); //Call dismiss (simulating clicking the cancel button on the modal)
expect( scope.canceled ).toBe( true );
});
Brant's answer was clearly awesome, but this change made it even better for me:
fakeModal =
opened:
then: (openedCallback) ->
openedCallback()
result:
finally: (callback) ->
finallyCallback = callback
then in the test area:
finallyCallback()
expect (thing finally callback does)
.toEqual (what you would expect)