How to make Object.assign work? - javascript

Background
I am trying to extend the functionality of an old object via Object.assign, by passing in a new object with an additional feature.
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
const test = () => {
printLog(); //fails here!
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();
Problem
My mix object fails execution, even though it has bot printLog and test methods:
Object {printLog: function, test: function}
Question
How can I fix my code so that the test function will work as expected?

In order to access printLog, you have to access it through this. However, your function test cannot be an arrow function because arrow functions use the this context of the context they're defined in, so to get the result you want, change printLog() into this.printLog() and switch test from an arrow function to a regular function:
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
const test = function() {
this.printLog(); //fails here!
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();

edit: Change your code to this:
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
function test() {
this.printLog();
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();

Related

Using Jest with NodeJS, Function in imported module not being mocked without using 'this' in main

In the setup below, if I run the test as is, myFunc is not mocked when I debug into handler.
However, if instead I add this. in front of the myFunc call in handler, then the function is mocked and everything works as expected.
Can someone please explain why this is? I'm new to mocking and can't see it.
I know what this does, but why won't jest mock without it since I told it to mock that function in the module?
index.js
const aws = require('aws-sdk')
exports.handler = async function (event, context) {
let s;
switch (event.func) {
case "myFunc":
console.log('Executing myFunc');
//making the call: s = await this.myFunc.apply(null, [event.params]) will make the mock work.
s = await myFunc.apply(null, [event.params])
console.log(s);
return s;
/*cases...*/
default:
// default behaviour
}
async myFunc({p1, p2}){
/* do something */
return x
}
exports.myFunc = myFunc
}
index.spec.js
jest.mock('./index.js', () => {
const allAutoMocked = jest.createMockFromModule('./index.js')
const actual = jest.requireActual('./index.js')
return {
__esModules: true,
...allAutoMocked,
myFunc : jest.fn().mockImplementation(() => ({ mockedValue: 'test' })),
handler: actual.handler
}
})
let index = require("./index.js")
describe('Test myFunc', () => {
test('If myFunc function was called', async () => {
var event = { func: 'myFunc', params: { p1: xx, p2: false } };
const context = {};
const logMock = jest.fn((...args) => console.log(...args));
const data = await handler(event, context);
})
})

Mock a function and used it as UUT with Jest in JS

I want to test one function from exported object in one describe and mock it in another function from the same exported object since the second function is using the first function.
// funcs.js
const func1 = () => {
return true;
};
const func2 = () => {
const bool = func1();
if (bool) {
// do something
} else {
// do else
}
};
export const funcs = {func1, func2};
// funcs.spec.js
const {funcs as uut} from './funcs';
describe('unit', () => {
describe('func 1', () => {
test('', () => {
const bool = uut.func1();
expect(bool).toBeTruthy();
});
});
describe('func 2', () => {
test('', () => {
jest.mock(uut.func1).mockReturnValue(false);
uut.func2();
// rest of test
});
});
});
I tried using jest.requireActual but did not work. What is the best approach for this if even possible?

How do these nested JavaScript functions work?

I have a question related to this code:
const somaHorasExtras = (salario, valorHorasExtras) => salario + valorHorasExtras;
const calculaDescontos = (salario, descontos) => salario - descontos;
const verifiqueSe = (valor) => {
const assercoes = {
ehExatamenteIgualA(esperado) {
if (valor !== esperado) {
// eslint-disable-next-line no-throw-literal
throw {};
}
},
};
return assercoes;
};
const teste = (titulo, funcaoDeTeste) => {
try {
funcaoDeTeste();
console.log(`${titulo} passou!`);
} catch {
console.error(`${titulo} não passou!!!`);
}
};
teste('somaHorasExtras', () => {
const esperado = 2500;
const retornado = somaHorasExtras(2000, 500);
verifiqueSe(retornado).ehExatamenteIgualA(esperado);
});
teste('calculaDesconto', () => {
const esperado = 2300;
const retornado = calculaDescontos(2500, 200);
verifiqueSe(retornado).ehExatamenteIgualA(esperado);
});
My question is related to the verifiqueSe function specifically. How does this function work? Does someone can explain how this function work in conjunction with the inner function ehExatamenteIgualA? What is the assercoes which is returned?
Thank you.
Your verifiqueSe(valor) function returns an object. You may find it a little confusing, since this syntax:
const foo = {
bar() {
//
}
};
is just a short syntax for object method:
const foo = {
bar: function () {
//
}
};
So in order to call the bar() function, you'd need to reach it through foo:
foo.bar();

Best way to write a function that either returns a value, or a resolved promise

So I am trying to write a logging HOC that will take a function and log the result of that function. I would like this hoc to be able to log the result of any function whether that function returns a promise or a value. This is what I have so far:
const logFn = (x) => {
return (...args) => {
const result = x(...args);
console.log(`result: ${result}`);
return result;
}
};
I would like to have this function handle the case when x returns a promise. I know a hacky way to do it (typeof result === object && typeof result.then === function) but this seems brittle. I am nearly sure there is a more elegant way to do this but I am struggling to find it.
I have included a failing jest test below:
import logFn from './logFn';
describe('logFn', () => {
let outputData;
beforeEach(() => {
const storeLog = inputs => (outputData += inputs);
console["log"] = jest.fn(storeLog);
require('./logFn');
outputData = ""
});
it('handles async functions', () => {
const add2P = (x, y) => Promise.resolve(x + y);
const logAdd2 = logFn(add2P);
const expected = add2P(1,2).then((data) => data);
const actual = logAdd2(1,2);
expect(outputData).toBe('result: 3');
expect(actual).toEqual(expected);
})
});
bonus points if you can help me clean up the beforeEach.
This has the unfortunate side effect of not logging synchronously, but you could try this.
const logFn = (x) => {
return (...args) => {
const result = x(...args);
Promise.resolve(result).then(function(value) {
console.log(`result: ${value}`);
})
return result;
}
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
While this answer isn't much different from #lemieuxster's answer, there is one major difference.
const logFn = fn => function () {
const result = fn.apply(this, arguments);
Promise.resolve(result).then(value => { console.log(`result: ${value}`); });
return result;
};
This preserves the calling context if, for example, you want to logify member methods:
const logFn = fn => function () {
const result = fn.apply(this, arguments);
Promise.resolve(result).then(value => { console.log(`result: ${value}`); });
return result;
};
const foo = {
bar: 'Hello, world!',
doSomething: logFn(function () {
return this.bar;
})
};
foo.doSomething();

Mocking chained methods

(I use Jest for testing)
For example, I have this function:
const find = () => {
return {
where: () => {
in: () => {}
}
};
};
and I call that in different place:
find('me').where('id').in(['123']);
How to mock and test calls in find(), where() and in()?
Here's a dirt simple mock interface:
const find = (findData) => {
const data = {
find: findData
};
const self = {
where: (whereData) => {
data.where = whereData;
return self;
},
in: (inData) => {
data.in = inData;
return self;
},
data
};
return self;
};
const res = find('me').where('id').in(['123']);
console.log(res.data);

Categories