Deep Diff Test Failures in Karma with Mocha - mocha.js

I am running the following test:
describe("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
a.should.deep.equal(b);
});
});
The test fails as expected, but the error message is not at all helpful.
AssertionError: expected { Object (a, b, ...) } to deeply equal { Object (a, b, ...) }
How would I get it so that it outputs a prettified json comparison instead?
Libraries I am currently using:
karma 0.12.1
karma-mocha 0.1.6
karma-mocha-reporter 0.3.0
karma-chai 0.1.0

You can change where the message gets truncated with the following:
chai.config.truncateThreshold = 0
So for your example:
var chai = require('chai');
var expect = chai.expect;
chai.config.truncateThreshold = 0;
describe.only("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
expect(a).to.deep.equal(b);
});
});
Which will result in:
AssertionError: expected { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 3 } } } to deeply equal { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 4 } } }
+ expected - actual
"b": 2
"c": {
"a": 1
"b": 2
+ "x": 4
- "x": 3
}
}
}

The mocha reporter has an option for this: showDiff: true
You can stick this in your karma config:
config.set({
frameworks: [ 'mocha', 'chai', ... ],
plugins: [
require('karma-mocha'),
require('karma-chai'),
require('karma-mocha-reporter'),
...
],
reporters: [ 'mocha', ... ],
mochaReporter: {
showDiff: true, // <-- This!
},
...
});

You can use assert-diff library to show only the difference when test fails.
var assert = require('assert-diff');
describe("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
assert.deepEqual(a, b);
});
});
this will give you an error with the difference
1) objects should equal:
AssertionError: { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 3 } } } deepEqual { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 4 } } }
{
c: {
c: {
- x: 4
+ x: 3
}
}
}

Related

GraphQL (A = a AND B = b) OR (A = b AND B = a)

I am new to GraphQL and I've been trying to come up with a simple query but I'm not getting the results I need.
Basically, I am writing a mutation to delete a row when the following conditions are met:
(A = a AND B = b) OR (A = b AND B = a)
However, I can't seem to figure out how to write it.
I tried doing something like:
delete_links(where: {_or: {_and: {a: {_eq: a}, b: {_eq: b}}}, {_and: {a: {_eq: b}, b: {_eq: a}}}) {
affected_rows
}
}
I am using Hasura on postgresql.
Basically I have a table called Links storing:
link_a | link_b
The problem is a link between item 9 and 2 in link can either be:
link_a | link_b
2 | 9
or
link_a | link_b
9 | 2
Hence I want my delete mutation to delete BOTH cases. However I cant seem to do a query (A = a AND B = b) OR (A = b AND B = a)
Since _or, _and is array. So, your mutation should look like this:
# in this example: typeof A = Int, typeof B = Int
mutation delete_links($a: Int, $b: Int) {
delete_links(
where: {
_or: [
{ A: { _eq: $a }, B: { _eq: $b } }
{ A: { _eq: $b }, B: { _eq: $a } }
]
}
) {
affected_rows
}
}
# if you'd like to use additional _and
mutation delete_links($a: Int, $b: Int) {
delete_links(
where: {
_or: [
{ _and: [{ A: { _eq: $a } }, { B: { _eq: $b } }] }
{ _and: [{ A: { _eq: $b } }, { B: { _eq: $a } }] }
]
}
) {
affected_rows
}
}

adding function to loops through

I need to search in a big json nested collection which have unique IDs recursively. The collection contains key values or nested arrays which contains keys. Keys can be anywhere in the object. Keys can be number or string.
Please note: Key values are unique if they are not in array. If they are in array, the key duplicates per items in array. For example,
"WebData": {
WA1: 3, //not in array so unique
WA3: 2, so unique
WA3: "NEO",
WebGroup : [
{ Web1: 1, //duplicate Web1
Web2: 2
},
{ Web1: 2, //duplicate Web2
Web2: 2
}]
}
What I want:
I will pass an array of keys in different variations for example
Not in Arrays: I will pass key return either their values or sum for example:
function(["WA1",""WA3", "RAE1"],"notsum")
If I pass (not sum)
["WA1",""WA3", "RAE1"]
and the operation is not "sum", it should return an array of their values from the collection
[3,2,1]
If I pass the same but operation is sum)
function(["WA1",""WA3", "RAE1"],"sum")
["WA1",""WA3", "RAE1"]
it should return sum from the collection
return 6
If in Array: If the value to search are in the array means they duplicate, then it should return me sum or their individual values again For example
["WEB1","Web2"]
. It could either return me,
[7,1] //Again total of 3+4, 0+1 //see in example
or
[[3,4],[0,1]] //Because values are duplicate and in array, just collect them
I need to do in an elegant way:
Full example of JSON:
{
version: "1.0"
submission : "editing"
"WebData": {
WA1: 3,
WA3: 2,
WA3: "NEO",
WebGroup : [
{ Web1: 3,
Web2: 0
},
{ Web1: 4,
Web2: 1
}]
},
"NonWebData": {
NWA1: 3,
NWA2: "INP",
NWA3: 2,
},
"FormInputs": {
FM11: 3,
FM12: 1,
FM13: 2,
"RawData" : {
"RawOverview": {
"RAE1" : 1,
"RAE2" : 1,
},
"RawGroups":[
{
"name": "A1",
"id": "1",
"data":{
"AD1": 'period',
"AD2": 2,
"AD3": 2,
"transfers": [
{
"type": "in",
"TT1": 1,
"TT2": 2,
},
{
"type": "out",
"TT1": 1,
"TT2": 2,
}
]
}
},
{
"name": "A2",
"id": "2",
"data":{
"AD1": 'period',
"AD2": 2,
"AD3": 2,
"transfers": [
{
"type": "in",
"TT1": 1,
"TT2": 2,
},
{
"type": "out",
"TT1": 1,
"TT2": 2,
}
]
}
}
]
},
"Other":
{ O1: 1,
O2: 2,
O3: "hello"
},
"AddedBy": "name"
"AddedDate": "11/02/2019"
}
I am not able to write a function here, which can do this for me, my code is simply searching in this array, and I loop through to find it, which is I am sure not the correct way.
My code is not elegant, and I am using somehow repetitive functions. This is just one snippet, to find out the keys in one level. I want only 1 or 2 functions to do all this
function Search(paramKey, formDataArray) {
var varParams = [];
for (var key in formDataArray) {
if (formDataArray.hasOwnProperty(key)) {
var val = formDataArray[key];
for (var ikey in val) {
if (val.hasOwnProperty(ikey)) {
if (ikey == paramKey)
varParams.push(val[ikey]);
}
}
}
}
return varParams;
}
One more test case if in Array: to Return only single array of values, without adding. (Update - I achieved this through editing the code following part)
notsumsingle: function (target, key, value) {
if (target[key] === undefined) {
target[key] = value;
return;
}
target.push(value);
},
"groupData": [
{
"A1G1": 1,
"A1G2": 22,
"AIG3": 4,
"AIG4": "Rob"
},
{
"A1G1": 1,
"A1G2": 41,
"AIG3": 3,
"AIG4": "John"
},
{
"A1G1": 1,
"A1G2": 3,
"AIG3": 1,
"AIG4": "Andy"
}
],
perform(["AIG2",""AIG4"], "notsum")
It is returning me
[
[
22,
41,
3
]
],
[
[
"",
"Ron",
"Andy"
]
]
Instead, can I add one more variation "SingleArray" like "sum" and "notsum" and get the result as single Array.
[
22,
41,
3
]
[
"",
"Ron",
"Andy"
]
4th one, I asked, is it possible the function intelligent enough to pick up the sum of arrays or sum of individual fields automatically. for example, in your example, you have used "sum" and "total" to identify that.
console.log(perform(["WA1", "WA3", "RAE1"], "total")); // 6
console.log(perform(["Web1", "Web2"], "sum")); // [7, 1]
Can the function, just use "sum" and returns single or array based on if it finds array, return [7,1] if not return 6
5th : I found an issue in the code, if the json collection is added this way
perform(["RAE1"], "notsum") //[[1,1]]
perform(["RAE1"], "sum") //2
It returns [1, 1], or 2 although there is only one RAE1 defined and please note it is not an array [] so it should not be encoded into [[]] array, just the object key
"RawData" : {
"RawOverview": {
"RAE1" : 1,
"RAE2" : 1,
}
For making it easier, and to take the same interface for getting sums or not sums and a total, without any array, you could introduce another operation string total for getting the sum of all keys.
This approach takes an object for getting a function which either add an value to an array at the same index or stores the value at an specified index, which match the given keys array of the function.
For iterating the object, you could take the key/value pairs and iterate until no more object is found.
As result, you get an array, or the total sum of all items.
BTW, the keys of an object are case sensitive, for example 'WEB1' does not match 'Web1'.
function perform(keys, operation) {
function visit(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (k in indices) return fn(result, indices[k], v);
if (v && typeof v === 'object') visit(v);
});
}
var result = [],
indices = Object.assign({}, ...keys.map((k, i) => ({ [k]: i }))),
fn = {
notsum: function (target, key, value) {
if (target[key] === undefined) {
target[key] = value;
return;
}
if (!Array.isArray(target[key])) {
target[key] = [target[key]];
}
target[key].push(value);
},
sum: function (target, key, value) {
target[key] = (target[key] || 0) + value;
}
}[operation === 'total' ? 'sum' : operation];
visit(data);
return operation === 'total'
? result.reduce((a, b) => a + b)
: result;
}
var data = { version: "1.0", submission: "editing", WebData: { WA1: 3, WA3: 2, WAX: "NEO", WebGroup: [{ Web1: 3, Web2: 0 }, { Web1: 4, Web2: 1 }] }, NonWebData: { NWA1: 3, NWA2: "INP", NWA3: 2 }, FormInputs: { FM11: 3, FM12: 1, FM13: 2 }, RawData: { RawOverview: { RAE1: 1, RAE2: 1 }, RawGroups: [{ name: "A1", id: "1", data: { AD1: 'period', AD2: 2, AD3: 2, transfers: [{ type: "in", TT1: 1, TT2: 2 }, { type: "out", TT1: 1, TT2: 2 }] } }, { name: "A2", id: "2", data: { AD1: 'period', AD2: 2, AD3: 2, transfers: [{ type: "in", TT1: 1, TT2: 2 }, { type: "out", TT1: 1, TT2: 2 }] } }] }, Other: { O1: 1, O2: 2, O3: "hello" }, AddedBy: "name", AddedDate: "11/02/2019" };
console.log(perform(["WA1", "WA3", "RAE1"], "notsum")); // [3, 2, 1]
console.log(perform(["WA1", "WA3", "RAE1"], "total")); // 6
console.log(perform(["Web1", "Web2"], "sum")); // [7, 1]
console.log(perform(["Web1", "Web2"], "notsum")); // [[3, 4], [0, 1]]
.as-console-wrapper { max-height: 100% !important; top: 0; }

Reactive JS (RxJs) Group by key

I have a data stream with e.g. the following values:
Observable.of(
[{time: 1000, a: 100},
{time: 1000, b: 100},
{time: 2000, a: 200}]
);
And need to merge the values based on time to get:
[{time: 1000, a: 100, b: 100},
{time: 2000, a: 200}]
I can use map and reduce but then I end up with a single map that I have to split somehow again. Is there a more straight forward way in RxJs?
You could just do an array reduce inside of a map operator. Might be a bit clearer than the groupBy and flatMap. This is more of a data mapping issue than an rxjs issue.
Rx.Observable.of(
[{time: 1000, a: 100},
{time: 1000, b: 100},
{time: 2000, a: 200}]
).map(data => {
return data.reduce((acc, cur) => {
const index = acc.findIndex(x => x.time === cur.time);
if (index >= 0) {
acc[index] = { ...acc[index], ...cur };
} else {
acc.push(cur);
}
return acc;
}, [])
})
.subscribe(x => { console.log('result', x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.min.js"></script>
I got this in the end:
Observable.of(
[{time: 1000, channelKey: 'a', value: 100},
{time: 1000, channelKey: 'b',value: 100},
{time: 2000, channelKey: 'a', value: 200}]
)
.flatMap<any[], any>(x => x)
.groupBy(v => Math.floor(v.time.getTime() / 1000), v => {
return {[v.channelKey]: v.value}
})
.flatMap((group$) => group$.reduce((acc, cur) => Object.assign(cur, acc), {time: group$.key}))
.toArray()
.subscribe((v) => {
console.log("Value: ", v)
})

Apply delta values on nested fields

Suppose I have record like this:
{
id: 1,
statistics: {
stat1: 1,
global: {
stat2: 3
},
stat111: 99
}
}
I want to make update on record with object:
{
statistics: {
stat1: 8,
global: {
stat2: 6
},
stat4: 3
}
}
And it should be added to current record as delta. So, the result record should looks like this:
{
id: 1,
statistics: {
stat1: 9,
global: {
stat2: 9
},
stat4: 3,
stat111: 99
}
}
Is it possible to make this with one query?
Do you want something generic or something specific?
Specific is easy, this is the generic case:
const updateValExpr = r.expr(updateVal);
const updateStats = (stats, val) => val
.keys()
.map(key => r.branch(
stats.hasFields(key),
[key, stats(key).add(val(key))],
[key, val(key)]
))
.coerceTo('object')
r.table(...)
.update(stats =>
updateStats(stats.without('global'), updateValExpr.without('global'))
.merge({ global: updateStats(stats('global'), updateValExpr('global'))
)
There might be some bugs here sincce it's untested but the solution key point is the updateStats function, the fact that you can get all the keys with .keys() and that coerceTo('object') transforms this array: [['a',1],['b',2]] to this object: { a: 1, b: 2 },
Edit:
You can do it recursively, although with limited stack (since you can't send recursive stacks directly, they resolve when the query is actually built:
function updateStats(stats, val, stack = 10) {
return stack === 0
? {}
: val
.keys()
.map(key => r.branch(
stats.hasFields(key).not(),
[key, val(key)],
stats(key).typeOf().eq('OBJECT'),
[key, updateStats(stats(key), val(key), stack - 1)],
[key, stats(key).add(val(key))]
)).coerceTo('object')
}
r.table(...).update(row => updateStats(row, r(updateVal)).run(conn)
// test in admin panel
updateStats(r({
id: 1,
statistics: {
stat1: 1,
global: {
stat2: 3
},
stat111: 99
}
}), r({
statistics: {
stat1: 8,
global: {
stat2: 6
},
stat4: 3
}
}))

Use of take in drop function of persisted list

I am reading Learning Rust With Entirely Too Many Linked Lists, specifically the chapter about a persistent singly-linked stack.
I am having difficulty understanding use of take in the drop function.
Without it, I get the same logs in drop.
use std::rc::Rc;
use std::fmt;
type Link<T> = Option<Rc<Node<T>>>;
#[derive(Debug)]
pub struct List<T>
where
T: fmt::Debug,
{
head: Link<T>,
}
#[derive(Debug)]
struct Node<T>
where
T: fmt::Debug,
{
val: T,
next: Link<T>,
}
impl<T> List<T>
where
T: fmt::Debug,
{
pub fn new() -> Self {
List { head: None }
}
pub fn append(&self, val: T) -> List<T> {
List {
head: Some(Rc::new(Node {
val: val,
next: self.head.clone(),
})),
}
}
}
impl<T> Drop for List<T>
where
T: fmt::Debug,
{
fn drop(&mut self) {
println!("1 : {:?}", self);
let mut curr_list = self.head.take();
println!("2");
while let Some(node) = curr_list {
println!("3");
match Rc::try_unwrap(node) {
Err(_) => {
println!("4");
break;
}
Ok(ref mut x) => {
println!("5");
curr_list = x.next.take()
}
}
println!("6");
}
println!("7");
}
}
fn main() {
let list = List::new().append(1).append(2);
let _list2 = list.append(3);
let _list3 = list.append(3);
let _list4 = list.append(3);
let _list5 = list.append(3);
}
Playground
It outputs:
1 : List { head: Some(Node { val: 1, next: None }) }
2
3
4 : stopping at 1
7
1 : List { head: None }
2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }
2
3
5: dropping 2
6
3
5: dropping 1
6
7
The first and second 1 : List { is because of first line in main, which is destroying temp lists created. The next 3 1 : List { are lists getting dropped in reverse order of creation. Finally the shared list of size 2 is dropped.
Even if I remove take from line : curr_list = x.next.take() and remove ref mut for x in fn drop I still get the same output.
What is x there and why does take() have no effects?
I earlier thought that take would change the original list by setting the next to None, but that is not possible as that will invalidate the list for other people who have references.
Implementing drop on Node :
impl<T> Drop for Node<T> where T: fmt::Debug {
fn drop(&mut self) {
println!("Node drop : {:?}", self.val);
}
}
so, Just after Ok(ref mut x) block, Node x is dropped.

Resources