How to change variable value from another module in javascript - javascript

I am using Webpack as bundler and I can't find answer to my question anywhere.
For example, I have file index.js which contains:
import { Func } from './func.js'
export let foo = 'bar';
Func();
console.log(foo);
I have another file, let's say func.js which contains:
import { foo } from './index.js';
export const Func = () => { foo = 'baz' }
But it isn't possible to change value of variable from another module.
How do you handle such situations if I don't want to move function 'Func' to index.js?
I also know it is possible to mutate objects but using an object is not always an option.

foo is a primitive. You can't change it's the value assigned to it in the other module when it's a primitive, you can only change the value foo has been assigned in scope of the current module.
You could always do it with functions however:
let foo = 'initial value';
export const getFoo = () => foo;
export const setFoo = (val) => (foo = val);
import { getFoo, setFoo } from 'someModule';
getFoo(); // initial value;
// call this when necessary
setFoo('jim');
import { getFoo } from 'someModule';
// when called after `setFoo` has been called in the other module
getFoo(); // 'jim'

Related

Is there a way to have a constructor within an already existing constructor?

I have the following function that acts a base constructor:
function Foo() = {}
...
exports Foo
It's an empty constructor, and is used by other functions which I don't want to change. Also, Foo is only being exported from the file.
Now I need to create a different constructor perhaps within Foo.
The following is what I'd have with enum as a standalone constructor. But how do I make it a part of Foo?
function enum(data) {
this.data = data
}
enum.prototype.getVal() { return this.data; }
var obj = new enum(5);
obj.getVal();
Taking a completely wild guess from your commnets.
exporting from the file is of no real concern. If you're just using Foo as a namespace to "hang" functions off of you can do this:
Enum.js
// all constructors should be capitalized
function Enum() { }
Enum.prototype.whatever ...
exports Enum
Foo.js
const Enum = require('./Enum');
// it's unclear why `Foo` is even a function to be honest
function Foo() { }
Foo.Enum = Enum;
exports Foo
someOtherFile.js
const Foo = require('./Foo');
const myEnumInstance = new Foo.Enum();

Stubbing method in same file using Sinon

I'm trying to unit test a function in a file while stubbing another function in the SAME file, but the mock is not being applied and the real method is being called. Here's an example:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = a(); // call a
// ...do stuff
}
And my test:
import * as actions from 'foo';
const aStub = sinon.stub(actions, 'a').returns('mocked return');
actions.b(); // b() is executed, which calls a() instead of the expected aStub()
Some restructuring can make this work.
I've used commonJS syntax. Should work in the same way in ES6 as well.
foo.js
const factory = {
a,
b,
}
function a() {
return 2;
}
function b() {
return factory.a();
}
module.exports = factory;
test.js
const ser = require('./foo');
const sinon = require('sinon');
const aStub = sinon.stub(ser, 'a').returns('mocked return');
console.log(ser.b());
console.log(aStub.callCount);
Output
mocked return
1
While the above does work, it's definitely a workaround as my linter was quick to inform.
I ended up separating modules and using proxyquire. This library allows you to easily substitute any / all exports with those of your choosing, sinon stub spy or mocks included. e.g. :
in b.js
export const fnB = () => 'hey there!';
in a.js
import { fbB } from 'b.js';
export const fnA = () => fbB();
in a.test.js
import { noCallThru } from 'proxyquire';
const proxyquireStrict = noCallThru();
const stubB = stub().returns('forced result');
const moduleA = proxyquireStrict('a.js', {
'b.js' : { fnB: stubB }
}).fnA;
console.log(fnA()); // 'forced result'
The method mentioned above (using a factory to collect the functions) works well; however, eslint will not like the use of a variable/function that has not yet been declared. Therefore I would recommend a slight modification:
// my-functions.js
export const factory = {};
export const funcA = () => {
return facory.funcB();
};
factory.funcA = funcA;
export const funcB = () => true;
factory.funcB = funcB;
// my-functions-test.js
import {factory, funcA, funcB} from './path/to/my-functions';
describe('MyFunctions | funcA', () => {
test('returns result from funcB call', () => {
const funcBStub = sinon.stub(factory, 'funcB').returns(false);
// Test that the function does not throw errors
let result;
expect(() => (result = funcA())).not.toThrow();
// Test that the return value is that of the mock rather than the original function
expect(result).toEqual(false);
// Test that the stub was called
expect(funcBStub.called).toEqual(true);
});
});
// Don't forget to test funcB independently ;)
The important distinction is to add the functions within the file to the factory as they are defined to avoid break eslint rules. The only case where this could cause issues is if you tried calling one of those functions within the same file before they have all been defined. Example:
// my-functions-1.js
export const factory = {};
export const funcA = () => {
factory.funcB();
};
factory.funcA = funcA;
// Since the code execution runs from top to bottom, calling funcA here means that funcB has not yet been added to factory
funcA(); // Throws an error since factory.funcB() is not a function (yet)
export const funcB = () => true;
factory.funcB = funcB;
I prefer this technique of using a "collector" to call functions within the same file since it is not always a great idea to create separate files for EACH function that you write. Often, I find that I will create many related utility functions in order to make my code more readable, reusable, and composable; putting each function into a separate file would make the code slightly more difficult to understand since a reader could not see the definitions of these functions without bouncing between different files.
I met with the same issue and found one method. You can change your foo.js file to this:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = exports.a(); // using "exports." to call a
// ...do stuff
}
Please refer to https://codeburst.io/stub-dependencies-with-sinon-js-259ac12379b9.

How to spy on function from another module

I have two functions in one module:
export function foo() {
console.log('foo');
}
export function bar() {
foo()
}
Now I want to test bar(), set a spy on foo() and assert for it to be called. How can this be achieved?
EDIT/update: Sorry had bar and foo backwards.
The way the module is currently structured.
When the code is executed, the bar reference inside function bar is resolved against the local implementation. You can't modify that since it's outside of the module code. There's no access to the intervals.
Have you tried using code like this for the test file?
let obj = {};
obj.bar = function () {
this.foo();
}
obj.foo = function() {
...
}
export default obj;

Does ES2015 exported class create a closure?

As it's currently compiled via Babel + Webpack, module's exported class will create a closure: variables created inside the module will be shared between class instances.
bar.js:
let foo;
export default class Bar {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
}
app.js:
import Bar from './bar.js';
var barOne = new Bar();
var barTwo = new Bar();
barOne.foo = 'quux';
console.assert(barTwo.foo === 'quux');
I wonder if this behavour correct according to the spec.
I wonder if this behavour correct according to the spec.
Yes. JavaScript has lexical scope. That doesn't change with classes.
Keep in mind that classes are more or less just syntactic sugar for constructor function + prototype. Would you have had the same question if you wrote
let foo;
function Bar(){};
Bar.prototype = {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
};
module.exports = Bar;
instead?

JavaScript design patterns: Injecting a dependency that is not yet created

I have a CommonJS module:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(foo);
// A value is given to foo after other-module has been initialised
foo = "bar";
}
As you can see, this requires other-module:
// other-module.js
module.exports = function (foo) {
function example() {
console.log(foo);
// > "bar"
}
}
I would like the example function inside of other-module to be aware of the foo variable inside of main-module, even though is it established after the module is required.
When other-module runs, foo will not be undefined. However, the point is that by time my example function runs, foo will have been given a value of bar.
The pattern above obviously does not work. What design pattern do I need to implement?
I'm not super-familiar with CommonJS, so this might not be the idiomatic way to do it, but using a function instead of a variable should work:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(function() { return foo; });
foo = "bar";
}
// other-module.js
module.exports = function (fooFn) {
function example() {
console.log(fooFn());
}
}
The foo value (a string) will be passed by value, so it's undefined inside other-module. You could use an options object that is passed by reference:
var options = {},
someModule = require('other-module')(options);
options.foo = "bar";

Categories