How to handle date picker in Cypress - angularjs

How to select a past date in the DOB field? What Javascript function can I use in Cypress automation?
It is not a free text field, only can select from the date picker. Here is the screenshot and the HTML
<input _ngcontent-kgi-c484="" id="dob" formcontrolname="dob" readonly=""
bsdatepicker="" placeholder="Optional" class="form-control
plore-form-control ng-valid ng-touched ng-dirty" ng-reflect-name="dob"
ng-reflect-bs-config="[object Object]"
ng-reflect-max-date="Fri Apr 16 2021 00:00:00 GMT+1">
I tried this function but it didn't work
cy.get('#dob').invoke('val').then((text) => {
expect('08/05/1999').to.equal(text);

What I did was add a custom command (we have various datepickers throughout our system, each having a slightly different selector).
Cypress.Commands.add("setDateInput", (selector, value) => {
// wait for the flatpickr instance to be applied before setting the date
// 'flatpickr-input' class is added on initiation
cy.get(`${selector}.flatpickr-input`).then($el => {
$el.get(0)._flatpickr.setDate(value, true)
})
});
Here, you can pass in a changing selector and then the DD/MM/YYYY format as parameters. Hope this helps someone.

The control is a bunch of buttons, you can click them in Cypress, e.g
cy.get('button').contains('8').click(); // select the 8th day
The chevrons (left and right) you'll need to click a few times,
cy.get('button.uib-left').click().click().click().click() // keep going for MM/YY
You can click on that middle part, but I can't figure that one out exactly.
Ok, I figured it out, click "April 2021" once to choose the month
cy.get('button').contains('April 2021').click();
// now select the month
cy.get('button').contains('May').click()
OR click the "April 2021" then "2021" to select the year
cy.get('button').contains('April 2021').click();
cy.get('button').contains('2021').click();
cy.get('button.uib-left').click().click() // get decade with 1999
// now select the year
cy.get('button').contains('1999').click()
But you get the idea, interact the way a user does.

Related

MomentJS providing time an hour behind what is selected

I seem to be having a bit of a weird bug wherein as the title states, MomentJS is providing a time that is an hour behind. This is my code so far:
import { AdapterMoment } from "#mui/x-date-pickers/AdapterMoment";
import moment from "moment";
...
const [job, setJob] = useState({
name: "",
outgoingDateTime: moment.now(),
jobStartDateTime: moment.now(),
returningDateTime: moment.now(),
jobFinishDateTime: moment.now(),
isJobStartLinked: jobStartLinked,
isJobFinishLinked: jobFinishLinked,
contact: null,
});
const handleOutgoingDateTimeChange = (newValue) => { setJob({...job, outgoingDateTime: newValue}); }
With the above code, when I trigger the DateTimePicker to be displayed, it displays the correct time. For example, if I trigger it on 19/09/2022 at 23:45, it will display 19/09/2022 23:45.
This is what I'm using to display this:
<LocalizationProvider dateAdapter={AdapterMoment}>
<DateTimePicker
label="Outgoing Date and Time"
value={job.outgoingDateTime}
onChange={handleOutgoingDateTimeChange}
inputFormat="DD/MM/YYYY HH:mm"
ampm={false}
renderInput={(params) => <TextField {...params} />} />
</LocalizationProvider>
Might I also add that when I change the value of the DateTimePicker, it correctly states the input. For example, let's say I input 25/09/2022 07:30. It would display 25/09/2022 07:30.
Now, when I then tap save, the returned value is an hour behind. So, for example, let's take what I entered just now 25/09/2022 07:30. It would come back as 25/09/2022 06:30.
I'm checking my back end to see if that was the issue, however, upon doing so, I could see that the front end is passing along the hour behind data.
What could be happening and how could I fix this?
So, after looking into this a little further, I found that my back end was using LocalDateTime which, living in the UK is bad... Bad because LocalDateTime is not Daylight Saving aware. After changing the variables to ZonedDateTime (which is DST aware) and zoning it in to Europe/London, it now saves to the database properly.

How can I get the date to show when component is first rendered? MERN stack

I've created a form the user fills out, and then can update. When the form renders to update, the date that is stored in the user's database entry won't show up. I get this error: The specified value "Mon Jul 27 1987 20:00:00 GMT-0400 (Eastern Daylight Time)" does not conform to the required format, "yyyy-MM-dd"
I have another form, and it seems to work just fine, but for some reason this form won't load the date upon rendering.
This is how the date is set when the form is originally submitted and updated:
<div>
<label>Date of birth</label>
<input name="dateOfBirth" label="Date of birth" type="date" value={dateOfBirth} onChange={(e)=> setDateOfBirth(e.target.value)} />
</div>
and this is how the state is loaded:
const HHForm = ({user, userState}) => {
const [dateOfBirth, setDateOfBirth] = useState(userState?.healthHistory[0]?.dateOfBirth ? ((userState?.healthHistory[0]?.dateOfBirth) : (''))
But when the component renders to update the form, the date is just left as an empty date selector, as if there is no date data, but the database has an entry for the dateOfBirth.
HTML 5 date pickers should be in format of yyyy-MM-dd. You should format your date. You can use moment to do that. https://www.npmjs.com/package/moment
import moment from 'moment'
setState(moment(your date here).format('YYYY-MM-DD'))
Here is full code https://codesandbox.io/s/date-picker-76lgw?file=/src/App.js

Cypress: cannot find elements in calendar popup

I cannot interact with the date picker (popup) in my Cypress tests.
I tried .find() and .get() on every div class but each time it says
Timed out retrying after 4000ms: Expected to find element: .cdk-overlay-container, but never found it
This is my test code:
cy.get('#signup-step-pers-details').within(() => {
cy.get('[name="firstName"]').type(user.firstName)
.get('[name="surname"]').type(user.lastName)
.get('#select-gender').click()
.get('.ng-dropdown-panel-items').contains(user.gender, {matchCase: false}).click()
.get('#input-dateOfBirth').click()
.find('.owl-dt-popup').click()
.get('.owl-calendar-year').contains(2002).click()
I tried adding some wait time but that didn't help either.
#KKhan is correct, the Angular Date Time Picker opens in a cdk-overlay-container at the foot of the document.
More detail on the layout:
<body>
...
<div id="signup-step-pers-details>
...
<div id="input-dateOfBirth"></div>
</div>
...
<div class="cdk-overlay-container">
<owl-date-time-container>
...
</owl-date-time-container>
</div>
</body>
Using cy.get('#signup-step-pers-details').within(() => { restricts commands inside to that section of the DOM, but the owl-date-time-container is outside of that.
You can use this approach Cypress how to temporarily escape from a cy.within()
cy.get('#signup-step-pers-details').within(() => {
// cy.root() === #signup-step-pers-details
cy.get('[name="firstName"]').type(user.firstName)
.get('[name="surname"]').type(user.lastName)
.get('#select-gender').click()
.get('.ng-dropdown-panel-items').contains(user.gender, {matchCase: false}).click()
.get('#input-dateOfBirth').click()
// shift cy.root() to date-time-picker
cy.document().its('body').find('owl-date-time-container').within(() => {
cy.get('button.owl-dt-control-period-button').click()
cy.contains('2002').click()
cy.contains('Aug').click()
cy.contains('23').click()
})
// back to cy.root() === #signup-step-pers-details
cy.get('#select-nationality').click()
})
Note I've used .owl-dt-control-period-button which is correct for the current version of Angular Date Time Picker, but perhaps you have an older version that requires .owl-calendar-year.
This sequence
.get('#input-dateOfBirth').click()
.find('.owl-dt-popup').click()
is expecting to find the date popup within the dateOfBirth control.
You may simply need
.get('#input-dateOfBirth').click()
.get('.owl-dt-popup').click()
Generally you see cy.get() for each item, not chaining all the gets as you have done. That still works because .get() always starts it's search at cy.root(), which is set to #signup-step-pers-details by the .within().
But the .find() is different, it starts it's search at the previous subject, which is the DOB control.
I should add, in case you were expecting the date popup to actually be inside the DOB input, that cdk-overlay-container is added when the popup is made visible, at the bottom of the <body></body> tag (take a look in devtools).
<div class="cdk-overlay-container">...</div>
</body>
Your approach of using contains is good but there is another syntax you may use for the purpose of selecting a date:
cy.get('#signup-step-pers-details').within(() => {
cy.get('[name="firstName"]').type(user.firstName)
.get('[name="surname"]').type(user.lastName)
.get('#select-gender').click()
.get('.ng-dropdown-panel-items').contains(user.gender, {matchCase: false}).click()
.get('#input-dateOfBirth').click()
.find('.owl-dt-popup').click()
.contains('.owl-calendar-year', '2002').click()

Disable an array of dates in a datepicker on Angular 2

I've got two calendars in a form. One is a starting date, and the other is the ending date. I'm using the 'ng-pick-datetime' (https://www.npmjs.com/package/ng-pick-datetime) to have a cross-browser calendar picker.
My goal is to block from date 0 (1st Jan 1970) to the date selected in the starting date calendar, in the ending date calendar picker.
So the thing here is to make sure the ending date is after the starting date.
For this, ng-pick-datetime' picker has the [disabledDates] property, which is waiting for an array of Dates that shouldn't be selectable.
What I'm trying is to bind this property to my array of forbidden dates, which is created in a function when the form is created, and also every time the ending date calendar gets focus.
I'm printing my array of forbidden dates to check if it is created correctly and if the dates included in it are between date 0 and the starting date selected. I looks like this part is working fine.
I don't get any browser console error. Just have the ending date calendar picker not blocking any date.
This is my template code:
<div class="input-control col-sm-6" [class.has-error]="startDate.invalid && startDate.dirty">
<label class="control-label" for="startDate">Starting Date *</label>
<owl-date-time
[(ngModel)]="data.startDate"
[dateFormat]="'DD-MM-YYYY'"
[inputId]="'startDate'"
[placeHolder]="'dd-mm-aaaa'"
[type]="'calendar'"
[dataType]="'date'"
[autoClose]="'true'"
id="startDate"
name="startDate"
#startDate="ngModel"
[disabled]="!paramsService.isSolicitante()"
[hideClearButton]
required>
</owl-date-time >
</div>
<div class="input-control col-sm-6" [class.has-error]="endDate.invalid && endDate.dirty">
<label class="control-label" for="endDate">Ending Date *</label>
<owl-date-time
[(ngModel)]="data.endDate"
[dateFormat]="'DD-MM-YYYY'"
[inputId]="'endDate'"
[placeHolder]="'dd-mm-aaaa'"
[type]="'calendar'"
[dataType]="'date'"
[autoClose]="'true'"
id="endDate"
name="endDate"
#endDate="ngModel"
[disabled]="!paramsService.isSolicitante()"
[hideClearButton]="!paramsService.isSolicitante()"
[disabledDates]="'forbiddenDates'"
(onFocus)="getForbiddenEndDates()"
required>
</owl-date-time >
</div>
//printing of selected date values:
<div class="col-sm-6">{{ data.startDate}}</div>
<div class="col-sm-6">{{ data.endDate}}</div>
{{ this.forbiddenDates }} //printing of the dates array to check it
And this is the component code (typescript), just the part that matters here:
forbiddenDates: Date[] = [];
ngAfterViewInit(): void { this.getForbiddenEndDates(); }
// This creates an array of Dates from the beginning of all times to the value of startDate
getForbiddenEndDates(): void {
let dateZero: Date = new Date(0);
let forbiddenDates: Date[] = [];
while (dateZero <= this.data.startDate){
forbiddenDates.push(new Date(dateZero));
dateZero.setDate(dateZero.getDate() + 1);
}
this.forbiddenDates = forbiddenDates;
}
Screenshot of the form and the forbidden dates array printed
I answer myself. It seems that this [disabledDates] template property doesn't change dynamically, so it's just for a fixed array of dates.
The solution is much simpler. Add this template property to the endDate input field:
[min]="data.startDate"

getting time and date using html 5 date type

I am developing android application using Cordova and ionic framework ,in which i am using Html 5 date type to get the date its works fine.
Now i want to select the time along with the date (ie user can select the time )
is it possible with html5 date type ??
Here is my code
<input type="date" ng-model="meetingData.enddate" />
$scope.submitForm=function(meetingData){
console.log(meetingData.enddate);
}
<input type="date"> does not have a feature to let pick time by user. You can set the current time as default through this whereas the date is selected by user.
var hour = new Date().getHours();
var mins = new Date().getMinutes();
$scope.meetingData.enddate.setHours(hour);
$scope.meetingData.enddate.setMinutes(mins);
Demo
Alternatively, You should look into ui-timepicker and ui-datepicker.

Resources