A couple of tests started to fail recently while running cypress with Chrome.
Test 1
Cypress fails to verify the text correctly. Here are the screenshots:
Text displayed on the UI
Text matched:
Here is how the number is generated in the code:
let dateString = '';
before(() => {
dateString = Date.now();
timestamp = `XXX.${dateString}`;
});
it('test to save data', () => {
// uses timestamp variable to save data
});
it('test to check data', () => {
// uses the same timestamp variable to check data
});
How can the value of timestamp variable differ between the two tests? Is the before method called again for each it block? If it is called again then how can I ensure both tests have the same value for the variable timestamp?
In this block dateString is not string it's a number, and the error looks like a rounding problem (last digit differs).
let dateString = '';
before(() => {
dateString = Date.now();
timeStamp = 'XXX.' + `${dateString}`;
})
Making dateString a proper string should solve the problem, as the characters will be locked in.
let dateString = '';
before(() => {
dateString = Date.now().toString()
timeStamp = `XXX.${dateString}` // BTW this is how string interpolation looks
})
Related
When working with a Faunadb record that contains a date value, I struggled with using that date in JavaScript. Eventually I got it working like so:
project.shipDate = new Date(await client.query(q.Format('%t', project.shipDate)));
This seems fine, but I also noticed I could do this:
let test = JSON.parse(JSON.stringify(project.created));
console.log(test);
datetest = new Date(test["#date"]);
Which seems wonky (grin), but may be quicker as it's not using the Fauna client library. Which should I prefer?
The JS driver has several helper classes that let you cast the javascript Time and Date objects to their FQL counterparts.
Here is an example.
From Fauna to JS
You can create a new document that contains a date value.
const project = await client.query(
q.Create(
q.Collection("projects"),
{ data: { shipDate: q.ToDate(q.Now()) } }
)
)
You can retrieve the date value and use as a javascript Date object by using the value property
const shipDate = new Date(project.data.shipDate.value)
From JS to Fauna
The date value can be modified however you want, and you can pass it back to FQL using the values.FaunaDate class.
const { values } = require('faunadb')
/* ... */
let nextDay = new Date(shipDate.getTime() + 86400000)
const faunaDate = new values.FaunaDate(nextDay)
Full Example
const project = await client.query(
q.Create(
q.Collection("projects"),
{ data: { shipDate: q.ToDate(q.Now()) } }
)
)
console.log(project)
const shipDate = new Date(project.data.shipDate.value)
console.log(shipDate)
let nextDay = new Date(shipDate.getTime() + 86400000)
console.log(nextDay)
const projectRef = project.ref
const projectUpdate = await client.query(
q.Update(
projectRef,
{ data: { shipDate: new values.FaunaDate(nextDay) } }
)
)
console.log(projectUpdate)
{
ref: Ref(Collection("projects"), "307924674409398337"),
ts: 1629918703380000,
data: { shipDate: Date("2021-08-25") }
}
2021-08-25T00:00:00.000Z
2021-08-26T00:00:00.000Z
{
ref: Ref(Collection("projects"), "307924674409398337"),
ts: 1629918703470000,
data: { shipDate: Date("2021-08-26") }
}
The response from server returns empty result despite just saving data earlier in that contextID with success. Most time it returns the json data but sometimes in between it returns empty string leading to createNewGameAsync() function instead of going directly to populateFromBackend() function. I am creating backend from https://glitch.com/edit/#!/panoramic-tendency project on glitch.
loadData: function () {
var contextID = FBInstant.context.getID();
console.log('loadData from ' + contextID);
FBInstant.player.getSignedPlayerInfoAsync(contextID)
.then(function (signedPlayerInfo) {
var url = 'https://panoramic-tendency.glitch.me' + '/get-match'
var sig = signedPlayerInfo.getSignature();
var method = 'POST'
var payload = { 'signature': sig };
return req(url, method, payload);
})
.then(function (result) {
if (result.empty) {
return this.createNewGameAsync();
} else {
return Promise.resolve(result.data);
}
}.bind(this)).then(function (backendData){
this.populateFromBackend(backendData);
}.bind(this))
.catch(function (error) {
this.displayError(error);
}.bind(this));
Solved. I was saving the FbInstant.Player.getPhoto() url as well in database. During encoding with getSignedPlayerInfoAsync() the signature generated was not valid format, and server couldn't decode it resulting in null value.
I want to test a view that has a list and filtering functionality:
I want to check the text of the first row and save it
Filter using that text
Check again that the same element is rendered
Thing is, when I match and element using element(by.id('some-id')), how can I retrieve info from that element (if it is possible) like the text it contains?
I created the detox-getprops npm package incorporating the hack mentioned by Maxime Helen. It allows retrieving the text and some other (platform-dependent) properties of the element.
const { getText } = require('detox-getprops');
const text = await getText(element(by.id('heading')));
expect(text).toEqual('Step One');
I hope Detox #445 will be resolved soon after which this package can be deprecated.
Update: You can now fetch the text on iOS using the getAttributes method. The detox-getprops library is still needed for Android (tracked using Detox #2083).
Hacky/funny workaround elaborated from this comment:
const readVisibleText = async (testID) => {
try {
await expect(element(by.id(testID))).toHaveText('_unfoundable_text');
throw 'We never should get here unless target element has unfoundable text';
} catch (error) {
if (device.getPlatform() === 'ios') {
const start = `accessibilityLabel was "`;
const end = '" on ';
const errorMessage = error.message.toString();
const [, restMessage] = errorMessage.split(start);
const [label] = restMessage.split(end);
return label;
} else {
// Android to be tested
const start = 'Got:';
const end = '}"';
const errorMessage = error.message.toString();
const [, restMessage] = errorMessage.split(start);
const [label] = restMessage.split(end);
const value = label.split(',');
var combineText = value.find(i => i.includes('text=')).trim();
const [, elementText] = combineText.split('=');
return elementText;
}
}
};
This is currently not supported, the progress is being tracked in this issue.
I'm running into this error when trying to use datePickerAndroid and setting the state afterwards.
Error Message
I feel like the problem may be from the initial state being a new Date() but not 100% sure.
_isAndroid = async () => {
let {action, year, month, day} = await DatePickerAndroid.open({
date: this.props.startDate,
});
if (action === DatePickerAndroid.dismissedAction) {
this.props.closeModal()
} else {
const date = year + "-" + month + "-" + day
this.props.onDateChange(date)
}
}
Prop Function:
onDateChange = (newDate) => {
this.setState({currentDate: newDate}) // <- This one is breaking
let dates = this.state.dates;
let index = this.state.currentIndex;
if (this.state.currentKey === "start") {
dates[index].start = newDate
} else {
dates[index].end = newDate
}
this.setState({dates: dates});
}
I've narrowed it down to the first setState, and I've tried making the initial state a string as well as setting the state to a simple string but still getting the error.
For DatePickerAndroid
expected dynamic type double
In other words native component wants time, but you put string. You this.props.startDate is string, transfer time in time format. Example:
const {action, year, month, day} = await DatePickerAndroid.open({
date: new Date() // <- This is Date, not string!
});
Good luck!
I'd like to use the dijit.calendar widget, but be able to set disabled dates from an array of dates. All the examples point out how to disable weekends, but I need to disable special dates too.
Can anyone point me in the right direction to utilize a custom function in the isDisabledDate, rather than just whats in dojo.date.locale?
I've tried writing a function, and putting it inside the isDisabledDate attribute, but all I get is errors.
I'm making a huge assumption here, that you're populating your array for each month displayed via an XHR request. This XHR request returns an array of strings in Y-m-d format (i.e. ['2011-11-29','2011-11-30']). Another slight assumption is that the XHR request returns an array of dates that should be enabled, but this can be reversed by swapping the disable = true; and disable = false; lines
I don't know how much detail to go into without being patronizing, so if anything is unclear I'll try to clarify afterwards.
dojo.provide("custom.Calendar");
dojo.declare("custom.Calendar", dijit.Calendar, {
_xhr: null,
// Month/Year navigation buttons clicked
_adjustDisplay: function(){
// Ensure all dates are initially enabled (prevents seepage)
this.isDisabledDate = function(date) {
return false;
};
this.inherited(arguments);
this._disableAndPopulate();
},
constructor: function(){
this.inherited(arguments);
this._disableAndPopulate();
},
// Month drop down box
_onMonthSelect: function(){
// Ensure all dates are initially enabled (prevents seepage)
this.isDisabledDate = function(date) {
return false;
};
this.inherited(arguments);
this._disableAndPopulate();
},
// Set disabled dates and re-render calendar
_disableAndPopulate: function(){
var currDate = this.currentFocus;
// Get Lower bound date
var startDate = new Date();
startDate.setFullYear(currDate.getFullYear(), currDate.getMonth(), -5);
// Create ymd dates manually (10x faster than dojo.date.locale.format)
var startMonth = (startDate.getMonth()<9 ? '0' + (startDate.getMonth()+1) : startDate.getMonth()+1);
var startDay = (startDate.getDate()<10 ? '0' + startDate.getDate() : startDate.getDate());
var ymdStartDate = startDate.getFullYear() + '-' + startMonth + '-' + startDay;
// Get Upper bound date
var endDate = new Date();
endDate.setFullYear(currDate.getFullYear(), currDate.getMonth() + 1, 14);
// Create ymd dates manually (10x faster than dojo.date.locale.format)
var endMonth = (endDate.getMonth()<9 ? '0' + (endDate.getMonth()+1) : endDate.getMonth()+1);
var endDay = (endDate.getDate()<10 ? '0' + endDate.getDate() : endDate.getDate());
var ymdEndDate = endDate.getFullYear() + '-' + endMonth + '-' + endDay;
var calendar = this;
// Get IssueDates
var issueDates;
// If an existing xhr request is still running, cancel it before starting a new one
if (this._xhr) {
this._xhr.cancel();
}
this._xhr = dojo.xhrGet({
url: "http://.....", // url of server-side script
content: {
startDate: ymdStartDate, // Earliest possible date displayed on current month
endDate: ymdEndDate, // Last possible date displayed on current month
filters: {} // Any additional criteria which your server-side script uses to determine which dates to return
},
failOk: true, // Prevent error being logged to console when previous XHR calls are cancelled
load: function(data){
issueDates = dojo.fromJson(data);
if (issueDates === undefined) {
// Error with xhr
} else {
calendar.isDisabledDate = function(date) {
var disable = true;
// Create ymdDate manually (10x faster than dojo.date.locale.format)
var month = (date.getMonth()<9 ? '0' + (date.getMonth()+1) : date.getMonth()+1);
var day = (date.getDate()<10 ? '0' + date.getDate() : date.getDate());
var ymdDate = date.getFullYear() + '-' + month + '-' + day;
// Loop through array returned from XHR request, if it contains current date then
// current date should not be disabled
for (key in issueDates) {
if (issueDates[key] == ymdDate) {
disable = false;
break;
}
}
return disable;
};
calendar._populateGrid(); // Refresh calendar display
}
},
// Log any errors to console (except when XHR request is cancelled)
error: function(args) {
if (args.dojoType == 'cancel') {
// Request cancelled
} else {
console.error(args);
}
}
});
},
onClose: function() {
// If an existing xhr request is still running, cancel it before starting a new one
if (this._xhr) {
this._xhr.cancel();
}
}
});
AMD style:
CalendarLite.js.uncompressed.js in dojo 1.7.1 contains the isDisabledDate function:
isDisabledDate: function(/*===== dateObject, locale =====*/){
// summary:
// May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
// dateObject: Date
// locale: String?
// tags:
// extension
/*=====
return false; // Boolean
=====*/
},
...
You could re-implement the function using this example:
var myCalendar = declare(Calendar, {
datesToDisable : [],
constructor: function(args) {
this.inherited("constructor", arguments);
this.datesToDisable = args.datesToDisable;
},
isDisabledDate: function(/*Date*/date, /*String?*/locale){
return array.some(this.datesToDisable, function(item) {
return dojo.compare(item, date, "date") === 0;
});
}
});
Then you can use the following constructor and datesToDisable parameter to specify your array.
var someCalendar = new myCalendar({datesToDisable: [new Date(...),....,new Date(....)]},...);
or try this for a fast and dirty solution:
var someCalendar = new Calendar(...);
someCalendar.datesToDisable = [new Date(...),....,new Date(....)];
someCalendar.isDisabledDate = function(/*Date*/date, /*String?*/locale){
return array.some(this.datesToDisable, function(item) {
return date.compare(item, date, "date") === 0;
});
}
But I would recommend the first approach. The assumption is that you know AMD style in order to "import" dijit/Calendar, dojo/_base/array and dojo/date (for "date.compare()" to work).
Cheers!
You can add list of holidays in an array with its timestamp and use indexOf method to find matching dates while populating the calendar in the overriding function of isDisabledDate
var holidays = new Array();
var holidDt = new Date("October 2, 2012");
holidays.push(holidDt.getTime());
Now access the holiday array and check its presence. If present disable, else enable by overriding the isDisabledDate function
isDisabledDate: function(d) {
var dt = new Date(d);
var dayN = dt.getDay();
dt.setHours(0, 0, 0, 0);
/**
* Condition for
* 1. Weekends
* 2. Holidays (holiday array needs to be updated with holiday times)
*/
return ((!((dayN > 0) && (dayN < 6))) || (arrayUtil.indexOf(holidays, dt.getTime()) >= 0));
}