I do have an issue when I want to decorate my export with a wrapper.
I have a wrapper/hof function that encapsulate the real function like this:
import { withSth } from './anotherFile'
import { someConst } from './someConst'
const myFunc = () => {}
export {
myFunc: withSth(someConst, myFunc)
}
Parsing error: ',' expected.
This does not work while this work:
import { withSth } from './anotherFile'
import { someConst } from './someConst'
const myFunc = () => {}
module.exports = {
myFunc: withSth(someConst, myFunc)
}
The only way i can do this is like this:
import { withSth } from './anotherFile'
import { someConst } from './someConst'
const myFuncX = () => {}
const myFunc = withSth(someConst, myFuncX)
// OR
// const myFync = withSth(someConst, () => {})
// but it lose readability
module.exports = {
myFunc
}
My point is how can I do the same thing with export and without using default export and renaming all my function
module.exports = {
methodA: withSth(param, methodA),
methodB: withSth(param, methodB),
methodC: withSth(param, methodC),
methodD: withSth(param, methodD),
}
Unlike Commonjs modules (with module.exports), ES6 modules do not export values but variable bindings. You must declare a variable1, you cannot export something unnamed. So your choices are only
export const myFunc = withSth(someConst, myFuncX);
const myFuncX = () => {};
export const myFync = withSth(someConst, () => {});
const myFuncX = () => {};
const myFyncY = withSth(someConst, () => {});
export { myFuncY as myFunc }
1: with the exception of export default …;, which implicitly declares a variable with an unforgeable name for you. But you want multiple named exports.
Svelte store documentation shows String or Integer being updated, but I did not find any dynamic function in store.
I don't understand how to make the getData function as a writable in order to notify the html of the change.
In the following sample, I would like b to be shown after the updateKey function is called.
You will find a minimal code in REPL here: https://svelte.dev/repl/3c86bd48d5b5428daee514765c926e58?version=3.29.7
And the same code here in case REPL would be down:
App.svelte:
<script>
import { getData } from './store.js';
import { updateKey } from './store.js';
setTimeout(updateKey, 1000);
</script>
<h1>{getData()}!</h1>
store.js
import {setContext} from 'svelte';
import {writable} from 'svelte/store';
var data = {
'a': 'a',
'b': 'b'
};
var key = 'a';
export const getData = function() {
return data[key];
}
export const updateKey = () => {
key = 'b';
}
The goal is to work with a dynamic function in the store.
Well, I think you still have a bit of confusion about how things work in Svelte... Not sure how to best answer your question, so here's some code for what's you're trying to achieve, along with some comments. I hope it will help you better understand how things come together in regards to stores.
App.svelte
<script>
import { onMount } from 'svelte'
import { key, data, updateKey } from './store.js'
onMount(() => {
// it's not safe to have an unchecked timer running -- problems would
// occur if the component is destroyed before the timeout has ellapsed,
// that's why we're using the `onMount` lifecycle function and its
// cleanup function here
const timeout = setTimeout(updateKey, 1000);
// this cleanup function is called when the component is destroyed
return () => {
clearTimeout(timeout)
}
})
// this will log the value of the `key` store each time it changes, using
// a reactive expression (a Sveltism)
$: console.log($key)
</script>
<!--
NOTE: we're using the $ prefix notation to access _the value_ of the store,
and not `data`, which would be _the store itself_ (an object with
subscribe, set, etc.)
-->
<h1>{$data}</h1>
store.js
import { writable, derived } from 'svelte/store'
const db = {
'a': 'a',
'b': 'b'
}
// a writable store with initial value 'a'
export const key = writable('a')
export const updateKey = () => {
// a writable store has a `set` method to change its value
key.set('b')
}
// you can use a derived store to compute derived values from
// the current value of other stores
//
// here, we're getting the value from the db when the value of
// the `key` store changes
export const data = derived([key], ([$key]) => db[$key])
if I understood your question correctly, you want to be able to change the function (logic) that is executed by getData() and you want on each function change the html to be updated
for this use case you'll need to create your own custom store
as follows in store.js
import { writable } from 'svelte/store';
// an object to hold our functions
const functions = {
"funcA": () => {
// do something
return "whatevedata for a"
},
"funcB": () => {
// do something
return "the data of b"
}
}
// this how to create a custom store, taken from svelte documentation
function createCustomStore(defaultValue) {
const { subscribe, set, update } = writable(defaultValue);
return {
subscribe,
//custom function change func where suppliedValue the value you input to the store
// set() is a default function for a store to change it's value
changeFunc: (suppliedValue) => set(functions[suppliedValue]),
reset: () => set(defaultValue)
};
}
export const getData = createCustomStore(() => "default");
export const updateKey = () => {
// this to update which function the store uses
getData.changeFunc("funcB")
}
in App.svelte
<script>
import { getData } from './store.js';
import { updateKey } from './store.js';
setTimeout(function() {
updateKey()
}, 1000);
</script>
<h1>{$getData()}</h1>
we added the $ to getData because it's a store that holds reference to functions and the () is there to execute any function referenced by getData store. since it is a store on each value change (function change) of getData, the html will be updated
here is a repl of the implementation
I am trying to deprecate a module with many named exports like so:
const Foo = () => 'foo';
const Bar = () => 'bar';
export { Foo };
export { Bar };
which is fine when consuming via:
import { Foo, Bar } from './something';
My thoughts about enabling deprecation warnings was to use a default export of type object with a property getter override for each key that prints the deprecation and then returns the module.
The shape then becomes something like:
const something = {};
Object.defineProperty(something, 'Foo', {
get(){
console.warn('Foo is deprecated soon');
return Foo;
}
});
// etc
export default something;
My thinking had been that the destructuring import would figure it out so
import { Foo, Bar } from './something';
... would continue to work as before. Instead, webpack complains that something does not have a named export Foo or Bar
using this, however, works:
const { Foo, Bar } = require('./something');
I can also have import something from './something'; const { Foo, Bar } = something and that works but it defeats the purpose if I have to refactor every import that exists.
So the question really is about how import { Foo, Bar } from './something'; works compared to the require() - I'd have thought that if the default export is an object, it would figure it out and destructure, but no joy.
Is there an easy way to do this 'proxying' without changing how the exports are being consumed elsewhere?
I think i made it work. Bare in mind that this is a workaround.
Given that you said that the library is being "re-exported" from a single file you could add an additional "layer" to the "re-export" where we turn the "re-exportation" file into a JS file and write our own associated typing file for it.
Working repl: https://repl.it/#Olian04/CelebratedKlutzyQuotes
Code snippets:
// index.ts
// consuming the library
import { Foo } from './demo';
console.log(Foo());
// library.ts
// the library it self
const Foo = () => 'foo';
export { Foo }
// demo.js
// the workaround implementation
const depricatedLibrary = require('./library');
const something = new Proxy(depricatedLibrary, {
get(obj, key) {
if (typeof key === 'string') {
console.warn(key + ' is deprecated soon');
}
return obj[key];
}
});
module.exports = something;
// demo.d.ts
// the workaround types
export * from './library';
I have a file that relies on an exported const variable. This variable is set to true but if ever needed can be set to false manually to prevent some behavior if downstream services request it.
I am not sure how to mock a const variable in Jest so that I can change it's value for testing the true and false conditions.
Example:
//constants module
export const ENABLED = true;
//allowThrough module
import { ENABLED } from './constants';
export function allowThrough(data) {
return (data && ENABLED === true)
}
// jest test
import { allowThrough } from './allowThrough';
import { ENABLED } from './constants';
describe('allowThrough', () => {
test('success', () => {
expect(ENABLED).toBE(true);
expect(allowThrough({value: 1})).toBe(true);
});
test('fail, ENABLED === false', () => {
//how do I override the value of ENABLED here?
expect(ENABLED).toBe(false) // won't work because enabled is a const
expect(allowThrough({value: 1})).toBe(true); //fails because ENABLED is still true
});
});
This example will work if you compile ES6 modules syntax into ES5, because in the end, all module exports belong to the same object, which can be modified.
import { allowThrough } from './allowThrough';
import { ENABLED } from './constants';
import * as constants from './constants';
describe('allowThrough', () => {
test('success', () => {
constants.ENABLED = true;
expect(ENABLED).toBe(true);
expect(allowThrough({ value: 1 })).toBe(true);
});
test('fail, ENABLED === false', () => {
constants.ENABLED = false;
expect(ENABLED).toBe(false);
expect(allowThrough({ value: 1 })).toBe(false);
});
});
Alternatively, you can switch to raw commonjs require function, and do it like this with the help of jest.mock(...):
const mockTrue = { ENABLED: true };
const mockFalse = { ENABLED: false };
describe('allowThrough', () => {
beforeEach(() => {
jest.resetModules();
});
test('success', () => {
jest.mock('./constants', () => mockTrue)
const { ENABLED } = require('./constants');
const { allowThrough } = require('./allowThrough');
expect(ENABLED).toBe(true);
expect(allowThrough({ value: 1 })).toBe(true);
});
test('fail, ENABLED === false', () => {
jest.mock('./constants', () => mockFalse)
const { ENABLED } = require('./constants');
const { allowThrough } = require('./allowThrough');
expect(ENABLED).toBe(false);
expect(allowThrough({ value: 1 })).toBe(false);
});
});
Unfortunately none of the posted solutions worked for me or to be more precise some did work but threw linting, TypeScript or compilation errors, so I will post my solution that both works for me and is compliant with current coding standards:
// constants.ts
// configuration file with defined constant(s)
export const someConstantValue = true;
// module.ts
// this module uses the defined constants
import { someConstantValue } from './constants';
export const someCheck = () => someConstantValue ? 'true' : 'false';
// module.test.ts
// this is the test file for module.ts
import { someCheck } from './module';
// Jest specifies that the variable must start with `mock`
const mockSomeConstantValueGetter = jest.fn();
jest.mock('./constants', () => ({
get someConstantValue() {
return mockSomeConstantValueGetter();
},
}));
describe('someCheck', () => {
it('returns "true" if someConstantValue is true', () => {
mockSomeConstantValueGetter.mockReturnValue(true);
expect(someCheck()).toEqual('true');
});
it('returns "false" if someConstantValue is false', () => {
mockSomeConstantValueGetter.mockReturnValue(false);
expect(someCheck()).toEqual('false');
});
});
There is another way to do it in ES6+ and jest 22.1.0+ thanks to getters and spyOn.
By default, you cannot spy on primitive types like boolean or number. You can though replace an imported file with your own mock. A getter method still acts like a primitive member but allows us to spy on it. Having a spy on our target member you can basically do with it whatever you want, just like with a jest.fn() mock.
Below an example
// foo.js
export const foo = true; // could be expression as well
// subject.js
import { foo } from './foo'
export default () => foo
// subject.spec.js
import subject from './subject'
jest.mock('./foo', () => ({
get foo () {
return true // set some default value
}
}))
describe('subject', () => {
const mySpy = jest.spyOn(subject.default, 'foo', 'get')
it('foo returns true', () => {
expect(subject.foo).toBe(true)
})
it('foo returns false', () => {
mySpy.mockReturnValueOnce(false)
expect(subject.foo).toBe(false)
})
})
Read more in the docs.
Thanks to #Luke I was able to expand on his answer for my needs. I had the requirements of:
Only mocking certain values in the file - not all
Running the mock only inside a single test.
Turns out that doMock() is like mock() but doesn't get hoisted. In addition requireActual() can be used to grab original data.
My config.js file - I need to mock only part of it
export const SOMETHING = 'blah'
export const OTHER = 'meh'
My test file
// import { someFunc } from 'some/file' // This won't work with doMock - see below
describe('My test', () => {
test('someFunc() does stuff', async () => {
// Here I mock the config file which gets imported somewhere deep in my code
jest.doMock('config.js', () => {
// Grab original
const originalModule = jest.requireActual('config')
// Return original but override some values
return {
__esModule: true, // Depends on your setup
...originalModule,
SOMETHING: 'boom!'
}
})
// Because `doMock` doesn't get hoisted we need to import the function after
const { someFunc } = await import(
'some/file'
)
// Now someFunc will use the original config values but overridden with SOMETHING=boom!
const res = await someFunc()
})
})
Depending on other tests you may also need to use resetModules() somewhere such as beforeAll or afterAll.
Docs:
doMock
requireActual
resetModules
Since we can't override/mock the value directly. we can use the below hack
// foo.js
export const foo = true; // could be expression as well
// spec file
import * as constants from './foo'
Object.defineProperty(constant, 'foo', {value: 1})
For functions:
Object.defineProperty(store, 'doOneThing', {value: jest.fn()})
For me the simplest solution was to redefine the imported object property, as decribed here:
https://flutterq.com/how-to-mock-an-exported-const-in-jest/
// foo.js
export const foo = true; // could be expression as well
// spec file
import * as constants from './foo'
Object.defineProperty(constant, 'foo', {value: 1, writable: true})
Facing the same issue, I found this blog post very useful, and much simpler than #cyberwombat use case :
https://remarkablemark.org/blog/2018/06/28/jest-mock-default-named-export/
// esModule.js
export default 'defaultExport';
export const namedExport = () => {};
// esModule.test.js
jest.mock('./esModule', () => ({
__esModule: true, // this property makes it work
default: 'mockedDefaultExport',
namedExport: jest.fn(),
}));
import defaultExport, { namedExport } from './esModule';
defaultExport; // 'mockedDefaultExport'
namedExport; // mock function
The most common scenario I needed was to mock a constant used by a class (in my case, a React component but it could be any ES6 class really).
#Luke's answer worked great for this, it just took a minute to wrap my head around it so I thought I'd rephrase it into a more explicit example.
The key is that your constants need to be in a separate file that you import, so that this import itself can be stubbed/mocked by jest.
The following worked perfectly for me.
First, define your constants:
// src/my-component/constants.js
const MY_CONSTANT = 100;
export { MY_CONSTANT };
Next, we have the class that actually uses the constants:
// src/my-component/index.jsx
import { MY_CONSTANT } from './constants';
// This could be any class (e.g. a React component)
class MyComponent {
constructor() {
// Use the constant inside this class
this.secret = MY_CONSTANT;
console.log(`Current value is ${this.secret}`);
}
}
export default MyComponent
Lastly, we have the tests. There's 2 use cases we want to handle here:
Mock the generate value of MY_CONSTANT for all tests inside this file
Allow the ability for a specific test to further override the value of MY_CONSTANT for that single test
The first part is acheived by using jest.mock at the top of your test file.
The second is acheived by using jest.spyOn to further spy on the exported list of constants. It's almost like a mock on top of a mock.
// test/components/my-component/index.js
import MyComponent from 'src/my-component';
import allConstants from 'src/my-component/constants';
jest.mock('src/my-component/constants', () => ({
get MY_CONSTANT () {
return 30;
}
}));
it('mocks the value of MY_CONSTANT', () => {
// Initialize the component, or in the case of React, render the component
new MyComponent();
// The above should cause the `console.log` line to print out the
// new mocked value of 30
});
it('mocks the value of MY_CONSTANT for this test,', () => {
// Set up the spy. You can then use any jest mocking method
// (e.g. `mockReturnValue()`) on it
const mySpy = jest.spyOn(allConstants, 'MY_CONSTANT', 'get')
mySpy.mockReturnValue(15);
new MyComponent();
// The above should cause the `console.log` line to print out the
// new mocked value of 15
});
One of the way for mock variables is the follow solution:
For example exists file ./constants.js with constants:
export const CONSTATN_1 = 'value 1';
export const CONSTATN_2 = 'value 2';
There is also a file of tests ./file-with-tests.spec.js in which you need to do mock variables.
If you need to mock several variables you need to use jest.requireActual to use the real values of the remaining variables.
jest.mock('./constants', () => ({
...jest.requireActual('./constants'),
CONSTATN_1: 'mock value 1',
}));
If you need to mock all variables using jest.requireActual is optional.
jest.mock('./constants', () => ({
CONSTATN_1: 'mock value 1',
CONSTATN_2: 'mock value 2'
}));
Instead of Jest and having trouble with hoisting etc. you can also just redefine your property using "Object.defineProperty"
It can easily be redefined for each test case.
This is a pseudo code example based on some files I have:
From localization file:
export const locale = 'en-US';
In another file we are using the locale:
import { locale } from 'src/common/localization';
import { format } from 'someDateLibrary';
// 'MMM' will be formatted based on locale
const dateFormat = 'dd-MMM-yyyy';
export const formatDate = (date: Number) => format(date, dateFormat, locale)
How to mock in a test file
import * as Localization from 'src/common/localization';
import { formatDate } from 'src/utils/dateUtils';
describe('format date', () => {
test('should be in Danish format', () => {
Object.defineProperty(Localization, 'locale', {
value: 'da-DK'
});
expect(formatDate(1589500800000)).toEqual('15-maj-2020');
});
test('should be in US format', () => {
Object.defineProperty(Localization, 'locale', {
value: 'en-US'
});
expect(formatDate(1589500800000)).toEqual('15-May-2020');
});
});
in typescript, you can not overwrite constant value but; you can overwrite the getter function for it.
const mockNEXT_PUBLIC_ENABLE_HCAPTCHAGetter = jest.fn();
jest.mock('lib/constants', () => ({
...jest.requireActual('lib/constants'),
get NEXT_PUBLIC_ENABLE_HCAPTCHA() {
return mockNEXT_PUBLIC_ENABLE_HCAPTCHAGetter();
},
}));
and in the test use as
beforeEach(() => {
mockNEXT_PUBLIC_ENABLE_HCAPTCHAGetter.mockReturnValue('true');
});
Thank you all for the answers.
In my case this was a lot simpler than all the suggestions here
// foo.ts
export const foo = { bar: "baz" };
// use-foo.ts
// this is just here for the example to have a function that consumes foo
import { foo } from "./foo";
export const getFoo = () => foo;
// foo.spec.ts
import "jest";
import { foo } from "./foo";
import { getFoo } from "./use-foo";
test("foo.bar should be 'other value'", () => {
const mockedFoo = foo as jest.Mocked<foo>;
mockedFoo.bar = "other value";
const { bar } = getFoo();
expect(bar).toBe("other value"); // success
expect(bar).toBe("baz"); // fail
};
Hope this helps someone.
../../../common/constant/file (constants file path)
export const Init = {
name: "",
basePath: "",
description: "",
thumbnail: "",
createdAt: "",
endDate: "",
earnings: 0,
isRecurring: false,
status: 0,
};
jest file
jest.mock('../../../common/constant/file',()=>({
get Init(){
return {isRecurring: true}
}
}))
it('showActionbutton testing',()=>{
const {result} = renderHook(() => useUnsubscribe())
expect(result.current.showActionButton).toBe(true)
})
index file
import {Init} from ../../../common/constant/file
const useUsubscribe(){
const showActionButton = Init.isRecurring
return showActionButton
}
I solved this by initializing constants from ContstantsFile.js in reducers. And placed it in redux store. As jest.mock was not able to mock the contstantsFile.js
constantsFile.js
-----------------
const MY_CONSTANTS = {
MY_CONSTANT1: "TEST",
MY_CONSTANT2: "BEST",
};
export defualt MY_CONSTANTS;
reducers/index.js
-----------------
import MY_CONST from "./constantsFile";
const initialState = {
...MY_CONST
}
export const AbcReducer = (state = initialState, action) => {.....}
ABC.jsx
------------
import { useSelector } from 'react-redux';
const ABC = () => {
const const1 = useSelector(state) => state. AbcReducer. MY_CONSTANT1:
const const2 = useSelector(state) => state. AbcReducer. MY_CONSTANT2:
.......
Now we can easily mock the store in test.jsx and provide the values to constant that we want.
Abc.text.jsx
-------------
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';
describe('Abc mock constants in jest', () => {
const mockStore = configureMockStore([thunk]);
let store = mockStore({
AbcReducer: {
MY_CONSTANT1 ="MOCKTEST",
MY_CONSTANT2 = "MOCKBEST",
}
});
test('your test here', () => { .....
Now when the test runs it will always pick the constant value form mock store.