I made a Single Page Application with React and everything was fine until I tested it on all the major browsers.
I used Mozilla during the development but then I tried it on other browsers and it worked on Edge, Explorer and Mozilla but it didn't on Chrome and Opera. All of the UI stuff works fine, and everything design related behaves well except the functionality that I made with React. So clicking on the Meal Types on the options dropdown, another list is supposed to appear on the page replacing the initial one with those 3 sections(Blog, Recipe, Tips). The application is supposed to expand further again by clicking on the Cookie section and again by clicking on the Horse section. As I said, all of this works fine except in Chrome and Opera. I want to make React behave as I described in Chrome and Opera too.
This is a link to the files
https://github.com/cristiAndreiTarasi/React_App
I expect that on clicking on the Meal Type option the app make those additional sections appear below - as it does in other browsers - in Chrome and Opera browsers and find what the problem is.
In your Header.jsx and Footer.jsx files you use class instead of className a few times, so you should correct that: https://reactjs.org/docs/faq-styling.html
Your problem is that you are registering an onClick on the <option> element, when you should be using the onChange prop on the <select> element itself, not the <option> element.
<select onChange={this.handleChange} className="custom-select mb-3">
<option selected>All</option>
<option value="mealType">Meal Type</option>
<option>Ingredients</option>
<option>World Cuisine</option>
<option>Cooking Style</option>
</select>
Your event handler looking like this:
handleChange = (event) => {
this.setState({
[event.target.value]: true,
});
}
Your state shouldn't be holding entire React components like it currently is, instead try something like this:
state = {
mealType: false,
}
With your render looking like this:
{this.state.mealType && <MealType click={this.handleClickTwo}/>}
As a general rule: state should contain data that a component's event handlers may change to trigger a UI update. this.state should only contain the minimal amount of data needed to represent your UI's state. See here for more details: http://web.archive.org/web/20150419023006/http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
Related
I have a project in which some components, such as dropdowns, are written in React.
In this case, I can't select an item from the dropdown because the DOM doesn't show what's in that dropdown.
<div class="Select__control css-1s2u09g-control"><div class="Select__value-container css-1d8n9bt"><div class="Select__placeholder css-14el2xx-placeholder" id="react-select-6-placeholder">Select...</div><input id="react-select-6-input" tabindex="0" inputmode="none" aria-autocomplete="list" aria-expanded="false" aria-haspopup="true" role="combobox" aria-readonly="true" aria-describedby="react-select-6-placeholder" class="css-1hac4vs-dummyInput" value=""></div><div class="Select__indicators css-1wy0on6"><div class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer" aria-hidden="true"><span></span></div></div></div>
How to conduct E2E tests in this case? Can someone explain or share their experience? I did not find information on the Internet. thank you
I looked for this component in the source code, but there are no files with react in the project code, these components are in node_modules, and it is not clear how to access this dropdown
This looks like the react-select control (judging by the classes).
This "hair-trigger" behavior makes it hard to find the options, the list disappears upon any mouse action.
The way I do it is
open the devtools
right-click the select, click inspect to find it in devtools
click the select on the page to open it, repeat a few times to open and close, watch the devtools
an element in devtools appears and disappears when menu is opened and closed. The element has format like this: <div id="react-select-6-listbox">, but the number in the id varies depending on how many selects are used on the page.
We now know the id of the options wrapper, so this is the test code:
cy.get('.Select__control')
.parent() // the top-level of react-select
.click() // open the list
cy.get('[id^="react-select"][id$="listbox"]') // the injected options wrapper
.within(() => {
cy.contains('5 - May').click() // select an option
})
cy.get('.Select__control')
.find('.Select__placeholder')
.should('contain', '5 - May') // verify selected text
If the 5 - May text is unique on the page you can just select it after opening the dropdown, but using .within() on the wrapper is safer.
I am building a fullStack project with react where you can create posts.
I am trying to use input type file to upload a picture, but when I click the choose file button, the pop up window does not appear. Here is the input:
<input type="file" onChange={e => setPhoto(e.currentTarget.files[0])} />
This isn't working. I tried changing onChange for onInput and it is still not working. I also looked around to make sure it wasn't nested inside another element that had e.stopPropagation or e.preventDefault. It is not. I tried placing it in different parts of my code and components and it still isn't working.
Something that I found curious is that, this issue is happening on Chrome. When I checked my localhost on Safari, the window where I can select the file pops up.
I have question regarding the development and testing workflow. I am using Cypress but this topic is suitable for any end to end test.
The question is how do you selecting the elements in the browser?
1, Explicit selectors like data-cy or automation-id on each element or component.
2, Selecting the elements by visible text on the screen and then navigate to specific element by DOM hierarchy.
Every test you write will include selectors for elements. To save yourself a lot of headaches, you should write selectors that are resilient to changes.
Oftentimes we see users run into problems targeting their elements because:
Your application may use dynamic classes or ID's that change
Your selectors break from development changes to CSS styles or JS behavior
Luckily, it is possible to avoid both of these problems.
Don't target elements based on CSS attributes such as: id, class, tag
Don't target elements that may change their textContent
Add data-* attributes to make it easier to target elements
<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-cy="submit"
>
Submit
</button>
And then for example clicking to button
cy.get("[data-cy=submit]")
.should("be.visible")
.click()
You can also search for specific text in dom.
cy.get("button")
.should("be.visible")
.contains("Submit")
.click()
Custom commmands commands.js
Cypress.Commands.add("sendBtn", () => {
cy.get("[data-cy=cy_send_btn]")
.should("be.visible")
.click()
})
And in test file
it("Add test description here", function() {
.
.
.
.
cy.sendBtn()
})
Custom command shown above you will be able to use multiple times in other test files for all send buttons. Your tests will be more isolated and efficient.
I have a custom directive (to exposecertain fields), and inside that I have another directive (the drop down box for the field). It's working well on Chrome, but on IE9 it appears the ng-show and ng-if is failing to evaluate. It appears not to even enter the function I defined (I put console.log inside the isAllowed function and it appears in Chrome but not in IE9).
<div>
<select id="" class="form-control" ng-model="measure" name="{{name}}">
<option ng-if="isAllowed(name, 1)" value="1">Kilowatt Hours</option>
<option ng-if="isAllowed(name, 2)" value="2">mmBTU</option>
<option ng-if="isAllowed(name, 3)" value="3">Therms</option>
<option ng-if="isAllowed(name, 4)" value="4">Decatherms</option>
</select>
</div>
I have tried ng-show instead of ng-if and it behaves the same in IE9. It appears the replace: true I put on my first directive is not honoured in IE9:
Whereas in Chrome this is replaced as expected with surrounding DIV elements and my custom directives cannot be seen anywhere, which is good.
Has anyone had experience of this before? Is it something to do with having a directive inside of a directive? Seems like IE9 does the first one OK then stops.
(I wish I could drop IE9 but it's an internal app and they're still on IE9 everywhere, so I've got to make it work somehow).
PS: The aim here is to only show the options that are relevant to the given field. In this case Electricity can be measured in kWh and mmBTUs but not in Therms and Decatherms. Inside the isAllowed function is supposed to be some switch logic. It works fine in Chrome, just not IE9, so I might need another method as a workaround.
PPS: Angular 1.3.2. IE9 - Browser Mode: IE9, Document Mode: IE9 Standards.
Figured it out. Isolated scope. Somehow Chrome was dealing with it OK, but IE9 was not.
In my app I have the fields I want to show to my user defined in a Partials module, but the drop-down lists is something I want to use in multiple places and they may change, so I defined them in a directive called BusinessRulesDirectives.
All I needed to do was drop in the BusinessRulesDirectives as a dependency to my Partials module and it works across both Chrome and IE9.
angular.module( 'ActualsPartials', [
'BusinessRulesDirectives'
] )
For some reason Chrome was able to run fine with this, but IE9 did not like it:
angular.module( 'ActualsPartials', [] )
Also, no errors were being output. I just happened to double-check for isolated scope as a wild guess.
Would be interested to know why Chrome was OK but IE9 was not.
Extjs prefers your app to be a single page app, but I'd still like to be able to do things like refresh my page and keep my current location in the app, and enter a url to get directly to a particular point in the app. Is there a solution for this?
Yes, I do the same in my app. You can use the Ext JS history mechanism to do so. Have a look at this example from Sencha.
You can listen to the history change event like this
Ext.History.on('change', function(token) {
// you navigate-to-target code goes here, e.g. change the viewport content
}
You can then initiate navigation by setting the browser hash to some navigation target
document.location.hash = yourNavigationToken;
This gives you also the ability to use deep-linking and forward/backward navigation with the browser buttons.
You need to init the history:
// The only requirement for this to work is that you must have a hidden field and
// an iframe available in the page with ids corresponding to Ext.History.fieldId
// and Ext.History.iframeId. See history.html for an example.
Ext.History.init();
and add an iframe and a hidden input field to your page, like in the example:
<form id="history-form" class="x-hide-display">
<input type="hidden" id="x-history-field" />
<iframe id="x-history-frame"></iframe>
</form>