I'm testing a Node.js application, in which addresses are stored in a Postgresql database using Sequelize. In order to test the 'getAll()' function, I wrote a test that does the following (see below):
1. create two addresses, and store them ('create' function of Sequelize)
2. call the getAll() function
3. (try to) assert that the returned array contains the created addresses, using expect.arrayContaining()
I tested the same setup without Sequelize in between (adding numbers/objects to an array and match a subset in the same way I did here), which works fine.
it("Should get all addresses", async () => {
const address_1 = await Address.create({
street: VALID_STREET,
number: VALID_NUMBER,
city: VALID_CITY,
country: VALID_COUNTRY
});
const address_2 = await Address.create({
street: "street 2",
number: "2",
city: "City 2",
country: "Country 2"
});
const allAddresses = await controller._getAll();
expect(allAddresses).toEqual(
expect.arrayContaining([address_1, address_2])
);
});
I expected the test to succeed, but it fails, giving me this errormessage that contains the two exact same arrays, except for the 'ArrayContaining' part.
expect(received).toEqual(expected) // deep equality
Expected: ArrayContaining [{"city": "A city", "country": "Belgium", "createdAt": 2019-08-21T14:05:23.063Z, "fullAddress": "valid street 123 A, A city, Belgium", "id": 296, "number": "123 A", "postalCode": null, "street": "valid street", "updatedAt": 2019-08-21T14:05:23.063Z}, {"city": "City 2", "country": "Country 2", "createdAt": 2019-08-21T14:05:23.066Z, "fullAddress": "street 2 2, City 2, Country 2", "id": 297, "number": "2", "postalCode": null, "street": "street 2", "updatedAt": 2019-08-21T14:05:23.066Z}]
Received: [{"city": "A city", "country": "Belgium", "createdAt": 2019-08-21T14:05:23.063Z, "fullAddress": "valid street 123 A, A city, Belgium", "id": 296, "number": "123 A", "postalCode": null, "street": "valid street", "updatedAt": 2019-08-21T14:05:23.063Z}, {"city": "City 2", "country": "Country 2", "createdAt": 2019-08-21T14:05:23.066Z, "fullAddress": "street 2 2, City 2, Country 2", "id": 297, "number": "2", "postalCode": null, "street": "street 2", "updatedAt": 2019-08-21T14:05:23.066Z}]
So, does anyone know how to fix this? Is this a Sequelize problem, or am I missing something here?
EDIT:
For people running into the same problem, I do have a workaround, which is to use the array.some() function, but this seems to be too verbose and I feel like the expect.arrayContaining() function should be used for this purpose.
expect(
allAddresses.some(address => {
address.id === address_2.id &&
address.street === address_2.street &&
address.number === address_2.number &&
address.city === address_2.city &&
address.country === address_2.country;
})
);
I think it's not a good idea to compare the whole Models (lot's of stuff you don't care about in there). Try to compare the dataValues instead. Make sure you don't use raw: true in your findAll call because then you don't have the dataValues property.
const allAddresses = await controller._getAll();
const addressesPlain = allAddresses.map(address => address.dataValues);
expect([address_1.dataValues, address_2.dataValues]).toEqual(addressesPlain);
If you're interested in the small test case I wrote: https://pastr.io/view/QKNmua
Another way to do it using arrayContaining matcher, not any better just a little more explicit IMO:
const allAddresses = await controller._getAll();
const addressesPlain = allAddresses.map(address => address.dataValues);
expect(addressesPlain).toEqual(expect.arrayContaining([address_1.dataValues, address_2.dataValues]);
I've found that searching for a single item in an array to be a little confusing using jest's matchers as well so for just checking that a single object is in an array this has been useful:
expect(addressesPlain).toContainEqual(address_1.dataValues)
toContainEqual, as their docs state, "recursively checks the equality of all fields, rather than checking for object identity." while toContain does check for objectIdentity which will fail with the above check.
Related
I want to register a new Contract Object.
However, when I try to register it together with ShippingAddress, I get an error.
How do I add a ShippingAddress with a Contract Object?
■ Field is not writeable: Contract.ShippingAddres
Contract cont = (Contract) parser.readValueAsStrict(Contract.class);
Address a = new Address();
a.country = 'Japan';
a.city = 'Tokyo';
cont.ShippingAddress = a;
insert cont;
I ran New Contract in the GUI, and the second of the arrays has ShippingAddress registered.
I would like to do this with the Apex API as well.
■ The ShippingAddress of the second record is registered.
[
{
"attributes": {
"type": "Contract",
"url": "/services/data/v56.0/sobjects/Contract/8000T000000223IQAQ"
},
"Id": "8000T000000223IQAQ",
"AccountId": "0010T00000Ox7sSQAR",
"BillingAddress": null,
"ShippingAddress": null,
"OwnerId": "0055g00000GRB5vAAH",
"Status": "Draft",
"StatusCode": "Draft",
"IsDeleted": false,
"ContractNumber": "00000114",
"CreatedDate": "2022-11-15T10:03:42.000+0000",
"CreatedById": "0055g00000GRB5vAAH",
"LastModifiedDate": "2022-11-15T10:03:42.000+0000",
"LastModifiedById": "0055g00000GRB5vAAH",
"SystemModstamp": "2022-11-15T10:03:42.000+0000",
"LastViewedDate": "2022-11-15T10:03:42.000+0000",
"LastReferencedDate": "2022-11-15T10:03:42.000+0000"
},
{
"BillingStreet": "西新宿1丁目",
"BillingCity": "新宿区",
"BillingState": "東京都",
"BillingPostalCode": "163-0590",
"BillingCountry": "日本",
"BillingAddress": {
"city": "新宿区",
"country": "日本",
"geocodeAccuracy": null,
"latitude": null,
"longitude": null,
"postalCode": "163-0590",
"state": "東京都",
"street": "西新宿1丁目"
},
"ShippingStreet": "西新宿1丁目",
"ShippingCity": "新宿区",
"ShippingState": "東京都",
"ShippingPostalCode": "163-0590",
"ShippingCountry": "日本",
"ShippingAddress": {
"city": "新宿区",
"country": "日本",
"geocodeAccuracy": null,
"latitude": null,
"longitude": null,
"postalCode": "163-0590",
"state": "東京都",
"street": "西新宿1丁目"
},
.....
}
]
https://developer.salesforce.com/docs/atlas.en-us.238.0.object_reference.meta/object_reference/compound_fields_address.htm
Standard address compound fields are read-only, and are only
accessible using the SOAP and REST APIs. See Compound Field
Considerations and Limitations for additional details of the
restrictions this imposes.
Instead set single fields inside the address.
cont.ShippingCountry = 'Japan';
cont.ShippingCity = 'Tokyo';
insert cont;
I have started to use this library and hit an issue.
Basically i have the following object structure which i receive from an api request.
{
"introduction": "hello",
"imageUri": "someimage.jpg",
"sections": [
{
"subSections": [
{
"sectionMedia": [
{
"externalUri": "https://vimeo.com/1212",
"id": 17127,
"type": "video",
"name": null,
"description": null,
"displayOrder": null,
}
],
"id": 172,
"name": "Section 1",
"displayOrder": 1,
},
{
"sectionMedia": [
{
"externalUri": "https://vimeo.com/1212",
"id": 178121,
"type": "video",
"name": null,
"description": null,
"displayOrder": null
}
],
"id": 178121,
"name": "Section 2",
"displayOrder": 2
},
],
"sectionMedia": [
{
"externalUri": "external.jpg",
"id": 176,
"type": "download",
"name": "Bar Modelling - Series 1 Workbook",
"description": null,
"displayOrder": null,
"createdAt": "2020-06-08T05:13:25+00:00",
"createdByUser": "/users/109",
"updatedAt": "2020-07-16T23:08:29+00:00",
"updatedByUser": "/users/109"
}
],
"id": 17111,
"name": "Series",
"description": "some description",
"displayOrder": 1,
]
}
So once the user has edited the data and this may not be all fields i need to submit and merge it with the object that we received and post full object back to the server.
However if i edit something within the array i need to show as the array name such as e.g if i updated the externalUri in sectionMedia with id 176 it should have the correct object structure when submitting the structure is flat like so:
name: "some name" externalUri: "newimage.jpg"
So wanted to see if there is a nice way to do this without actually searching the object and replacing when doing an onblur as will affect performance
Hope this makes sense
Not sure whether this is what you want but we can loop through the object
const [ fields, setFields ] = useState(
{
"externalUri": "external.jpg",
"id": 176,
"type": "download",
"name": "Bar Modelling - Series 1 Workbook",
"description": null,
"displayOrder": null,
"createdAt": "2020-06-08T05:13:25+00:00",
"createdByUser": "/users/109",
"updatedAt": "2020-07-16T23:08:29+00:00",
"updatedByUser": "/users/109"
})
We render the inputs here.
return Object.keys(fields).map( item => <input name={item} value={fields[item]} onChange={onChange} />
Then for the onchange.. we use the input name and add it back to the object.
const onChange = (e) => {
const value = e.target.value
const name = e.target.name
setFields( prev => ({ ...fields, [name]: value})) //this retains the original object, but change only the edited field
}
THOUGH.. submitting back the entire document back to the server is probably bad practice.
You should probably only submit fields that were changed.
WHY?
Because we cannot trust anything submitted from client, if you merge and resubmit the entire document, you need to make sure you re-validate the ENTIRE document.
I have the following HTTP Post with the following payload
{
"externalCode": "999",
"name": "PNNL - Winthrop, WA (Sundown L",
"description": "Winthrop",
"geozoneFlx": "PNL",
"status": "A",
"address1": "135 Sundown Lane",
"city": "WINTHROP",
"state": "WA",
"county": "OKANOGAN",
"country": "USA",
"zipCode": "98862-0339",
"timezone": "PST",
"startDate": "2016-01-27T00:00:00",
"endDate": "9999-12-31T00:00:00"
},
HOWEVER, some data message come into the Logic App looking like this with no "State" "name" in the data like this
"externalCode": "999",
"name": "PNNL - Winthrop, WA (Sundown L",
"description": "Winthrop",
"geozoneFlx": "PNL",
"status": "A",
"address1": "135 Sundown Lane",
"city": "WINTHROP",
"county": "OKANOGAN",
"country": "USA",
"zipCode": "98862-0339",
"timezone": "PST",
"startDate": "2016-01-27T00:00:00",
"endDate": "9999-12-31T00:00:00"
},
I have to say if the data message comes in without the State json Name like above, kick it out. How do I filter for a missing json field such as "State" in the above??
Thanks
Mike
I think you can judge whether the length of the value of the state field is greater than 0, if it is greater than 0, execute your original logic, if the length of the value is 0, you don't need to do anything. The design of the logic app is as follows:
If the request body of your http request is a json array, you can use the for each loop to process.
The expression for obtaining the length of the state field in condition is as follows:
length(coalesce(body('Parse_JSON')?['state'], ''))
For the usage of coalesce and length, you can refer to the official documentation
I have been working on a Mongo database for a while. The database has some visits that have this form:
[
{
"isPaid": false,
"_id": "5c12bc3dcea46f9d3658ca98",
"clientId": "5c117f2d1d6b9f9182182ae4",
"came_by": "Twitter Ad",
"reason": "Some reason",
"doctor_services": "Some service",
"doctor": "Dr. Michael",
"service": "Special service",
"payments": [
{
"date": "2018-12-13T21:23:05.424Z",
"_id": "5c12cdb9b236c59e75fe8190",
"sum": 345,
"currency": "$",
"note": "First Payment"
},
{
"date": "2018-12-13T21:23:07.954Z",
"_id": "5c12cdbbb236c59e75fe8191",
"sum": 100,
"currency": "$",
"note": "Second payment"
},
{
"date": "2018-12-13T21:23:16.767Z",
"_id": "5c12cdc4b236c59e75fe8192",
"sum": 5,
"currency": "$",
"note": "Third Payment"
}
],
"price": 500,
"createdAt": "2018-12-13T20:08:29.425Z",
"updatedAt": "2018-12-13T21:42:21.559Z",
}
]
I need to find some query to update some field of a single payment based on the _id of the visit and _id of the payment that is inside of nested array. Also when you update a payment's sum to some number so that the sum of all payments is greater than or equal to price the field isPaid is automatically updated to true.
I have tried some queries in mongoose to achieve the first part but none of them seem to work:
let paymentId = req.params.paymentId;
let updatedFields = req.body;
Visit.update(
{ "payments._id": paymentId },
{
$set: {
"visits.$": updatedFields
}
}
).exec((err, visit) => {
if (err) {
return res.status(500).send("Couldn't update payment");
}
return res.status(200).send("Updated payment");
});
As for the second part of the question I haven't really come up with anything so I would appreciate at least giving some direction on how to approach it.
Here is the code I have. It currently returns an array full of objects. How can i return an array full of the object ids, instead?
var ref = new Firebase('https://zip-it.firebaseio.com/zips');
$scope.detectChangeDigit1 = function() {
var query = ref.orderByChild("digit1").equalTo($scope.zipCode.firstDigit.toString());
$scope.digit1Array = $firebaseArray(query);
};
A few of your JSON objects (add these to your question next time please):
"20195": {
"city": "ALTURAS",
"digit1": "9",
"digit2": "6",
"digit3": "1",
"digit4": "0",
"digit5": "1",
"population": "3969",
"state": "CA",
"zipCode": "96101"
},
"20196": {
"city": "BLAIRSDEN-GRAEAGLE",
"digit1": "9",
"digit2": "6",
"digit3": "1",
"digit4": "0",
"digit5": "3",
"population": "1434",
"state": "CA",
"zipCode": "96103"
},
You're using AngularFire, which builds on top of the Firebase JavaScript SDK. That API will always load entire nodes, it has no option to only load object IDs.
To just get the IDs, you have a few options:
keep a separate list of only the IDs and load from that.
use the REST API, which supports a shallow=true parameter
prevent the query altogether and add a list of IDs for each digit1 value
Option 1 is tricky, given that you do an orderByChild().
Option 2 will not work either, since you cannot combine shallow=true with other query parameters.
Option 3 is likely going to be most performant. You still have two sub-options in there:
Store the entire objects under digit1:
"by_digit1":
"9":
"20195": {
"city": "ALTURAS",
"digit1": "9",
"digit2": "6",
"digit3": "1",
"digit4": "0",
"digit5": "1",
"population": "3969",
"state": "CA",
"zipCode": "96101"
},
"20196": {
"city": "BLAIRSDEN-GRAEAGLE",
"digit1": "9",
"digit2": "6",
"digit3": "1",
"digit4": "0",
"digit5": "3",
"population": "1434",
"state": "CA",
"zipCode": "96103"
},
Store only the ID of each object under the "index":
"by_digit1":
"9":
"20195": true,
"20196": true,
With both these two structure, you can immediately access the list of items that you're looking for with:
ref.child('by_digit1').child('9')
With this last structure you'll then look up each city in the main list.
ref.child('by_digit1').child('9').on('value', function(snapshot) {
snapshot.forEach(function(child) {
var cityRef = ref.child('zips').child(child.key());
cityRef.once('value', function(citySnapshot) {
console.log(citySnapshot.val());
});
});
})