Is there a way to make assertions only on selected array elements? - mocha.js

Let's say I want to check if an array contains an element with a certain value of a field that fulfills a given assertion, for eg.:
{ array: [ { element1: Mario, element2: White }, { element1: Luigi, element2: Green } ] }
Here I want to check that the element of array which has element1 equal to Mario has element2 equal to White. How can I do so with chai/supertest (or other npm packages)?

You can do it with jsonpath module:
var jp = require('jsonpath');
expect(jp.query(json, '$..array[?(#.element1=="Mario")]')[0].element2).to.equal('White')

Related

Getting the number of a specific elements inside a div on Cypress

How to get the number of divs that contain 'userid' from the div with id="chatListHolder"
https://i.stack.imgur.com/QzzLh.png
If a command that yields an element finds more than one element, it will yield all of them. So, we can then check the yielded array of element's length.
cy.get('#chatListHolder')
.should('have.length', 1); // we can change that 1 to whatever number we'd like
// or if we need to do something with that
cy.get('#chatListHolder')
.its('length').should('be.gt', 1);
// or another possibility
cy.get('#chatListHolder')
.its('length')
.then((length) => {
// whatever needs to be done with the length variable
});

Using N-Grams to search within a table of string Xcode, swift 3

Below is my code for the current search, right now it only checks string by string. How do I implement ngram into it? This code checks an array of strings compared to what the user types in on the front end. It generates results with that string.
ngram is a solution i found online for what i need. However, what i want is the ability for users to search in the array without the use of spaces, say the array is "I love sushi and popcorn,...." and the user searches "I love popcorn" the array which consist of the string "I love sushi and popcorn" will not show up. However, I want it to be.
One option is to write a function that puts each string seperated by space into another array and have the search function run through a loop in that array and do this for each other strings. However, I find this inefficient.
Please let me know if there are other solutions. Thanks
func updateSearchResults(for searchController: UISearchController) {
// filter results
// reload table
let searchString:String = searchController.searchBar.text!
self.dataToDisplay = self.sampleData.filter({ (dataString:String) -> Bool in
let match = dataString.range(of: searchString, options: NSString.CompareOptions.caseInsensitive)
if match != nil {
return true
}
else {
return false
}
})
self.pdfArrSearch = self.pdfArr.filter({ (dataString:String) -> Bool in
let match = dataString.range(of: searchString, options: NSString.CompareOptions.caseInsensitive)
if match != nil {
return true
}
else {
return false
}
})

Is there an Array equality match function that ignores element position in jest.js?

I get that .toEqual() checks equality of all fields for plain objects:
expect(
{"key1":"pink wool","key2":"diorite"}
).toEqual(
{"key2":"diorite","key1":"pink wool"}
);
So this passes.
But the same is not true for arrays:
expect(["pink wool", "diorite"]).toEqual(["diorite", "pink wool"]);
There does not seem to be a matcher function that does this in the jest docs, i.e. that tests for the equality of two arrays irrespective of their elements positions. Do I have to test each element in one array against all the elements in the other and vice versa? Or is there another way?
There is no built-in method to compare arrays without comparing the order, but you can simply sort the arrays using .sort() before making a comparison:
expect(["ping wool", "diorite"].sort()).toEqual(["diorite", "pink wool"].sort());
You can check the example in this fiddle.
As already mentioned expect.arrayContaining checks if the actual array contains the expected array as a subset.
To check for equivalence one may
either assert that the length of both arrays is the same (but that wouldn't result in a helpful failure message)
or assert the reverse: That the expected array contains the actual array:
// This is TypeScript, but remove the types and you get JavaScript
const expectArrayEquivalence = <T>(actual: T[], expected: T[]) => {
expect(actual).toEqual(expect.arrayContaining(expected));
expect(expected).toEqual(expect.arrayContaining(actual));
};
This still has the problem that when the test fails in the first assertion one is only made aware of the elements missing from actual and not of the extra ones that are not in expected.
Put the elements into a set. Jest knows how to match these.
expect(new Set(["pink wool", "diorite"])).toEqual(new Set(["diorite", "pink wool"]));
this does not answer the question exactly, but still may help people that end up here by google search:
if you only care that a subset of the array has certain elements, use expect.arrayContaining() https://jestjs.io/docs/en/expect#expectarraycontainingarray
e.g.,
expect(["ping wool", "diorite"])
.toEqual(expect.arrayContaining(["diorite", "pink wool"]));
Another way is to use the custom matcher .toIncludeSameMembers() from jest-community/jest-extended.
Example given from the README
test('passes when arrays match in a different order', () => {
expect([1, 2, 3]).toIncludeSameMembers([3, 1, 2]);
expect([{ foo: 'bar' }, { baz: 'qux' }]).toIncludeSameMembers([{ baz: 'qux' }, { foo: 'bar' }]);
});
It might not make sense to import a library just for one matcher but they have a lot of other useful matchers I've find useful.
What about checking the content and the length?
expect(resultArray).toEqual(expect.arrayContaining(expectedArray));
expect(resultArray.length).toEqual(expectedArray.length);
If you want to compare two arrays in JEST use the bellow model.
Official link: https://jestjs.io/docs/en/expect#expectarraycontainingarray
const array1 = ['a', 'b', 'c'];
const array2 = ['a', 'b', 'c'];
const array3 = ['a', 'b'];
it("test two arrays, this will be true", () => {
expect(array1).toEqual(expect.arrayContaining(array2));
});
it("test two arrays, this will be false", () => {
expect(array3).toEqual(expect.arrayContaining(array1));
});
You can combine using sets as stated in this answer with checking length of actual result and expectation. This will ignore element position and protect you from duplicated elements in the same time.
const materials = ['pink wool', 'diorite'];
const expectedMaterials = ['diorite', 'pink wool'];
expect(new Set(materials)).toEqual(new Set(expectedMaterials));
expect(materials.length).toBe(expectedMaterials.length);
EDIT: As there is suggested in comment below, this will only work for arrays with unique values.
If you don't have array of objects, then you can simply use sort() function for sorting before comparison.(mentioned in accepted answer):
expect(["ping wool", "diorite"].sort()).toEqual(["diorite", "pink wool"].sort());
However, problem arises if you have array of objects in which case sort function won't work. In this case, you need to provide custom sorting function.
Example:
const x = [
{key: 'forecast', visible: true},
{key: 'pForecast', visible: false},
{key: 'effForecast', visible: true},
{key: 'effRegForecast', visible: true}
]
// In my use case, i wanted to sort by key
const sortByKey = (a, b) => {
if(a.key < b.key) return -1;
else if(a.key > b.key) return 1;
else return 0;
}
x.sort(sortByKey)
console.log(x)
Hope it helps someone someday.
Still a work in progress, but this should work albeit, the error messages may not be clear:
expect.extend({
arrayContainingExactly(receivedOriginal, expected) {
const received = [...receivedOriginal];
if (received.length !== expected.length) return {
message: () => `Expected array of length ${expected.length} but got an array of length ${received.length}`,
pass: false,
};
const pass = expected.every((expectedItem, index) => {
const receivedIndex = findIndex(received, receivedItem => {
if (expectedItem.asymmetricMatch) return expectedItem.asymmetricMatch(receivedItem);
return isEqual(expectedItem, receivedItem);
});
if (receivedIndex === -1) return false;
received.splice(receivedIndex, 1);
return true;
});
return {
message: () => 'Success',
pass,
}
}
});
Then use it like this:
expect(['foo', 'bar']).arrayContainingExactly(['foo']) // This should fail
or
expect({foo: ['foo', 'bar']}).toEqual({
foo: expect.arrayContainingExactly(['bar', 'foo'])
}) // This should pass
We are looping through each value and removing it from the received array so that we can take advantage of the asymmetric matching provided by Jest. If we just wanted to do direct equivalency this could be simplified to just compare the 2 sorted arrays.
Note: This solution uses findIndex and isEqual from lodash.
You can use jest toContainEqual to check if an array contains an element. Then just do that for each element in your expected array:
const actual = [{ foobar: 'C' }, { foo: 'A' }, { bar: 'B' }];
const expected = [{ foo: 'A' }, { bar: 'B' }, { foobar: 'C' }];
expect(actual).toContainEqual(expected[0]);
expect(actual).toContainEqual(expected[1]);
expect(actual).toContainEqual(expected[2]);
(Or put the expect statement in a loop if you have too many elements to check)

Access variable hash depth values with square brackets notation

Given this hash:
hash1= { node1: { node2: { node3: { node4: { node5: 1 } } } } }
We access inside nodes with square brackets like this:
hash1[:node1][:node2][:node3][:node4]
Now I have a hash that I know will always be nested as it is an XML response from a SOAP webservice, but neither the depth of the hash nor the names of the nodes stay the same. So it would be nice if I could ask the user of my application for the hash depth and store it in a variable. And then be able to do hash1[:hash_depth] and achieve the same result as above.
I have accomplished what I want by the following code:
str = 'node1,node2,node3,node4'
str_a = str.split(',')
hash_copy = hash1
str_a.each { |s| hash_copy = hash_copy.[](s.to_sym) }
hash_copy
=> {:node5=>1}
hash1[:node1][:node2][:node3][:node4]
=> {:node5=>1}
that is asking the user to enter the hash depth separated by commas, store it in a string, split it, make an array, clone the original hash, go down each level and modify the hash till I get to the desired node. Is there a way to do it with the square brackets notation and using a variable to store the depth without modifying the hash or needing to clone it?
Edit:
someone answered with the following (can't see his post anymore???)
hash_depth="[:node1][:node2][:node3][:node4]"
eval "hash1#{hash_depth}"
Although eval does everything you need, there is another approach, since you already have the working code for comma-separated list:
hash_depth="[:node1][:node2][:node3][:node4]"
csh = hash_depth.gsub(/\A\[:|\]\[:|\]\Z/, { '][:' => ',' })
#⇒ "node1,node2,node3,node4"
And now you are free to apply your existing function to csh.
If this is a webapp, I think you should prepare a list of short textareas, which starts with a single text item, and the user can keep adding a new item to the list by clicking on a button. The areas will be filled by the user, and will be sent.
Then, you will probably receive this through some serialized form. You decode this to get an array of strings:
str_a = ["node1", "node2", "node3", "node4"]
and you can reach the inner element by doing:
str_a.inject(hash1){|h, s| h[s.to_sym]} #=> {:node5 => 1}

Iterate an array of hashes

I have a hash with a key of cities and the value is an array of hashes containing location data. It looks like this:
#locations = {
"cities"=>[
{"longitude"=>-77.2497049, "latitude"=>38.6581722, "country"=>"United States", "city"=>"Woodbridge, VA"},
{"longitude"=>-122.697236, "latitude"=>58.8050174, "country"=>"Canada", "city"=>"Fort Nelson, BC"},
...
]
}
I'd like to iterate through and print all the values for the key city:
Woodbridge, VA
Fort Nelson, BC
...
I can't say why would you have that structure, anyway, in the data format you have above, you would access it like
#locations[1].each { |c| p c["city"] }
Although, this implies that you should always expect second object in the array to be the required cities array. Further you need to put in required nil check.
For your corrected data format:
#locations = { "cities"=>[
{ "longitude"=>-77.2497049,
"latitude"=>38.6581722,
"country"=>"United States",
"city"=>"Woodbridge, VA"},
{ "longitude"=>-122.697236,
"latitude"=>58.8050174,
"country"=>"Canada",
"city"=>"Fort Nelson, BC" }] }
#locations["cities"].each { |h| puts h["city"] }
Woodbridge, VA
Fort Nelson, BC
or to save in an array:
#locations["cities"].each_with_object([]) { |h,a| a << h["city"] }
#=> ["Woodbridge, VA", "Fort Nelson, BC"]
As suggested by others, you have to do the exact same thing but let me explain whats happening in there.
Your example is an array and has multiple elements which could be just string like cities or an array of hashes like you mentioned.
So in order to iterate through the hashes and get the city values printed, you first of all have to access the array that has hashes. By doing so
#locations["cities"]
=> [{"longitude"=>-77.2497049, "latitude"=>38.6581722, "country"=>"United States", "city"=>"Woodbridge, VA"}, {"longitude"=>-122.697236, "latitude"=>58.8050174, "country"=>"Canada", "city"=>"Fort Nelson, BC"}]
Now that you have go the array you required, you can just integrate through them and get the result printed like this
#locations["cities"].map{|hash| p hash['city']}
In case your getting nil errors as you have stated in comments, just see what happens when you try to access the array of hashes. if you still are experiencing issues, then you may have to provide the full input so as to understand where the problem is.

Resources