Jest - Object is being re-used across tests - javascript

I have a simple function to test. I am using jest, and I am assigning in every it("") statement, an assertion constant, with my ArrayOfObjects.
While the first test passes. All other tests fail, cause they are using the object(assertion) from the first test.
How can I teardown the constant value in every test? Or in general fix it? Here is the code:
describe('Fn: CreateEdges', () => {
it('should RETURN [1 Key]', () => {
const assertion = [
{
identifier: {
name: '1'
}
}
];
const expectation = [
{
key: '1'
}
];
expect(createFn(assertion)).toEqual(expectation);
});
it('should RETURN [2 Keys]', () => {
const assertion = [
{
identifier: {
name: '1',
},
identifier: {
name: '2'
}
}
];
const expectation = [
{
key: '1',
},
{
key: '2',
}
];
expect(createFn(assertion)).toEqual(expectation); // This fails cause it is using the Object from test1
});
});
The createFn below:
import * as R from 'ramda';
function createnFn(array: any[]) {
return R.flatten(
array.map(({ identifier }: any) =>
identifier.key.map((marker: { name: string }) => ({
source: identifier.name,
target: marker.name,
}))
)
);
}
export default R.memoizeWith(R.identity, createFn);

As it was already mentioned, memoization causes the problem, it makes the function stateful. Non-memoized createnFn is local to the module, only memoized version of it is exported. Since it's reused between multiple tests, this results in test cross-contamination.
The solution is to re-import the module. It should be imported in tests not on top level but in tests, re-import is done with jest.isolateModules or jest.resetModules:
beforeEach(() => {
jest.resetModules();
})
it('should RETURN [1 Key]', () => {
const createFn = require('...').default;
...
expect(createFn(assertion)).toEqual(expectation);
});

Ciao, you problem could be related to function memoization.
Basically, Memoization is a technique that stores values in cache to improve performances. Try to remove R.memoizeWith(R.identity, createFn) and problem should disappears.

Related

how can I dynamically get the variables in javascript?

I am working on React app, but I think this is most likely JavaScript problem. I have many variables with a pattern, VARIABLE_NAME_{number}, example, FOO_1, FOO_2 ... so on. In my function, it takes index as input and return mapped output.
import power from 'customClass';
const getOneOfFoo = (theIndex) => {
power()
.then(data => {
let result = data?.first?.second?.FOO_{theIndex}?.name ; // how can I declare this one with passing input?
// example, if theIndex=59, I want to have
// let result = data?.first?.second?.FOO_59?.name;
resolve({
result: result
});
})
.catch(err => console.log(err))
});
The data object structure is like this,
data
|-first
|-second
|-FOO_1
|-name
|-FOO_2
|-name
|-FOO_3
|-name
|-FOO_4
|-name
...
In line 5, I want to assign result dynamically. How can I achieve this?
You can treat it like a dictionary.
Here's an example:
const data = {
'FOO_1': { name: 'Kenobi' },
'FOO_2': { name: 'Skywalker' },
'FOO_3': { name: 'Yoda' },
'FOO_4': { name: 'Kylo' },
'FOO_5': { name: 'Sidious' }
}
function getVar(index) {
let result = data?.[`FOO_${index}`]?.name;
return result;
}
console.log(getVar(1)); // expected output: Kenobi
console.log(getVar(2)); // expected output: Skywalker
console.log(getVar(3)); // expected output: Yoda
console.log(getVar(4)); // expected output: Kylo
console.log(getVar(5)); // expected output: Sidious
console.log(getVar(6)); // expected output: undefined
So for your case, it would probably be something like this:
import power from 'customClass';
const getOneOfFoo = (theIndex) => {
power()
.then(data => {
let result = data?.first?.second?.[`FOO_${theIndex}`]?.name;
resolve({
result: result
});
})
.catch(err => console.log(err))
});
And btw, resolve doesn't seem to be defined.
let result = data?.first?.second[`FOO_${theIndex}`]?.name ;
u can use [] with inside is string which is name of property

Check array equality with Jest

I've got a method inside the file test.ts:
public async listComponentsDiffer(lastTag: string, workDir: string): Promise<any[]>
This method return me a array like this :
[{ components: "toto", newVersion: "2", oldVersion: "1" }]
I'm trying to use Jest and I'm doing this for check this method:
test("correct array form", () => {
// Given
const lastag = "";
const workDir = ".";
// When
const result = ComponentsService.listComponentsDiffer(lastag, workDir);
// Then
const expected = [{ components: "toto", newVersion: "2", oldVersion: "1" }];
expect(result).toBe(expected);
});
But I've got thsi error :
TypeError: test_1.test.listComponentsDiffer is not a function Jest
How can I do my test ?
This method is an instance method, not a class method. Need to be called from an instance of the class.
This method uses async/await syntax, you need to add async/await to your test case as well.
Instead of using .toBe, you should use .toEqual.
Use .toEqual to compare recursively all properties of object instances (also known as "deep" equality)
E.g.
test.ts:
export class ComponentsService {
public async listComponentsDiffer(lastTag: string, workDir: string): Promise<any[]> {
return [{ components: 'toto', newVersion: '2', oldVersion: '1' }];
}
}
test.test.ts:
import { ComponentsService } from './test';
describe('60667611', () => {
test('correct array form', async () => {
const lastag = '';
const workDir = '.';
const instance = new ComponentsService();
const result = await instance.listComponentsDiffer(lastag, workDir);
const expected = [{ components: 'toto', newVersion: '2', oldVersion: '1' }];
expect(result).toEqual(expected);
});
});
unit test results:
PASS stackoverflow/60667611/test.test.ts (7.968s)
60667611
✓ correct array form (6ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.014s

How to mock a user module differently in each test?

I have the following unit test for my Vue component:
import { shallowMount } from '#vue/test-utils';
import OrganizationChildren from './OrganizationChildren.vue';
describe('OrganizationChildren', () => {
beforeEach(() => {
jest.resetModules();
});
it('passes', () => {
jest.doMock('#/adonis-api', () => {
return {
organization: {
family(id) {
return {
descendants: [],
};
},
},
};
});
const wrapper = shallowMount(OrganizationChildren, {
propsData: {
org: {
id: 1,
},
},
});
});
});
And in the Vue component, it does import { organization } from '#/adonis-api';. I'm temporarily just console.logging the imported organization object, to make sure it's correct. But I can see that it's not using the mocked version that I've specified. What am I doing wrong? My goal is to mock the family method differently in each it() block to test what happens if descendants is empty, if it contains 5 items, 100 items, etc.
Solved! I had a couple issues, as it turns out:
Not properly mocking #/adonis-api. I should mention that it only mocks stuff at the top level, so I had to use a factory function in jest.mock (see below).
I needed an await flushPromises() to allow the template to re-render after its created() method evaluated my mock function and stored the result in this.children.
Full test:
import { shallowMount, config } from '#vue/test-utils';
import flushPromises from 'flush-promises';
import OrganizationChildren from './OrganizationChildren.vue';
import { organization } from '#/adonis-api';
jest.mock('#/adonis-api', () => ({
organization: {
family: jest.fn(),
},
}));
describe('OrganizationChildren', () => {
config.stubs = {
'el-tag': true,
};
it('shows nothing when there are no children', async () => {
organization.family.mockResolvedValueOnce({
descendants: [],
});
const wrapper = shallowMount(OrganizationChildren, {
propsData: {
org: {
id: 1,
},
},
});
await flushPromises();
const h4 = wrapper.find('h4');
expect(h4.exists()).toBe(false);
});
it('shows children when provided', async () => {
organization.family.mockResolvedValueOnce({
descendants: [{ name: 'One' }, { name: 'Two' }],
});
const wrapper = shallowMount(OrganizationChildren, {
propsData: {
org: {
id: 1,
},
},
});
await flushPromises();
const h4 = wrapper.find('h4');
const list = wrapper.findAll('el-tag-stub');
expect(h4.exists()).toBe(true);
expect(list.length).toBe(2);
expect(list.at(0).text()).toBe('One');
expect(list.at(1).text()).toBe('Two');
});
});

Determine which dependency array variable caused useEffect hook to fire

Is there an easy way to determine which variable in a useEffect's dependency array triggers a function re-fire?
Simply logging out each variable can be misleading, if a is a function and b is an object they may appear the same when logged but actually be different and causing useEffect fires.
For example:
React.useEffect(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d])
My current method has been removing dependency variables one by one until I notice the behavior that causes excessive useEffect calls, but there must be a better way to narrow this down.
I ended up taking a little bit from various answers to make my own hook for this. I wanted the ability to just drop something in place of useEffect for quickly debugging what dependency was triggering useEffect.
const usePrevious = (value, initialValue) => {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
};
const useEffectDebugger = (effectHook, dependencies, dependencyNames = []) => {
const previousDeps = usePrevious(dependencies, []);
const changedDeps = dependencies.reduce((accum, dependency, index) => {
if (dependency !== previousDeps[index]) {
const keyName = dependencyNames[index] || index;
return {
...accum,
[keyName]: {
before: previousDeps[index],
after: dependency
}
};
}
return accum;
}, {});
if (Object.keys(changedDeps).length) {
console.log('[use-effect-debugger] ', changedDeps);
}
useEffect(effectHook, dependencies);
};
Below are two examples. For each example, I assume that dep2 changes from 'foo' to 'bar'. Example 1 shows the output without passing dependencyNames and Example 2 shows an example with dependencyNames.
Example 1
Before:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
After:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2])
Console output:
{
1: {
before: 'foo',
after: 'bar'
}
}
The object key '1' represents the index of the dependency that changed. Here, dep2 changed as it is the 2nd item in the dependency, or index 1.
Example 2
Before:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
After:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2], ['dep1', 'dep2'])
Console output:
{
dep2: {
before: 'foo',
after: 'bar'
}
}
#simbathesailor/use-what-changed works like a charm!
Install with npm/yarn and --dev or --no-save
Add import:
import { useWhatChanged } from '#simbathesailor/use-what-changed';
Call it:
// (guarantee useEffect deps are in sync with useWhatChanged)
let deps = [a, b, c, d]
useWhatChanged(deps, 'a, b, c, d');
useEffect(() => {
// your effect
}, deps);
Creates this nice chart in the console:
There are two common culprits:
Some Object being pass in like this:
// Being used like:
export function App() {
return <MyComponent fetchOptions={{
urlThing: '/foo',
headerThing: 'FOO-BAR'
})
}
export const MyComponent = ({fetchOptions}) => {
const [someData, setSomeData] = useState()
useEffect(() => {
window.fetch(fetchOptions).then((data) => {
setSomeData(data)
})
}, [fetchOptions])
return <div>hello {someData.firstName}</div>
}
The fix in the object case, if you can, break-out a static object outside the component render:
const fetchSomeDataOptions = {
urlThing: '/foo',
headerThing: 'FOO-BAR'
}
export function App() {
return <MyComponent fetchOptions={fetchSomeDataOptions} />
}
You can also wrap in useMemo:
export function App() {
return <MyComponent fetchOptions={
useMemo(
() => {
return {
urlThing: '/foo',
headerThing: 'FOO-BAR',
variableThing: hash(someTimestamp)
}
},
[hash, someTimestamp]
)
} />
}
The same concept applies to functions to an extent, except you can end up with stale closures.
UPDATE
After a little real-world use, I so far like the following solution which borrows some aspects of Retsam's solution:
const compareInputs = (inputKeys, oldInputs, newInputs) => {
inputKeys.forEach(key => {
const oldInput = oldInputs[key];
const newInput = newInputs[key];
if (oldInput !== newInput) {
console.log("change detected", key, "old:", oldInput, "new:", newInput);
}
});
};
const useDependenciesDebugger = inputs => {
const oldInputsRef = useRef(inputs);
const inputValuesArray = Object.values(inputs);
const inputKeysArray = Object.keys(inputs);
useMemo(() => {
const oldInputs = oldInputsRef.current;
compareInputs(inputKeysArray, oldInputs, inputs);
oldInputsRef.current = inputs;
}, inputValuesArray); // eslint-disable-line react-hooks/exhaustive-deps
};
This can then be used by copying a dependency array literal and just changing it to be an object literal:
useDependenciesDebugger({ state1, state2 });
This allows the logging to know the names of the variables without any separate parameter for that purpose.
As far as I know, there's no really easy way to do this out of the box, but you could drop in a custom hook that keeps track of its dependencies and logs which one changed:
// Same arguments as useEffect, but with an optional string for logging purposes
const useEffectDebugger = (func, inputs, prefix = "useEffect") => {
// Using a ref to hold the inputs from the previous run (or same run for initial run
const oldInputsRef = useRef(inputs);
useEffect(() => {
// Get the old inputs
const oldInputs = oldInputsRef.current;
// Compare the old inputs to the current inputs
compareInputs(oldInputs, inputs, prefix)
// Save the current inputs
oldInputsRef.current = inputs;
// Execute wrapped effect
func()
}, inputs);
};
The compareInputs bit could look something like this:
const compareInputs = (oldInputs, newInputs, prefix) => {
// Edge-case: different array lengths
if(oldInputs.length !== newInputs.length) {
// Not helpful to compare item by item, so just output the whole array
console.log(`${prefix} - Inputs have a different length`, oldInputs, newInputs)
console.log("Old inputs:", oldInputs)
console.log("New inputs:", newInputs)
return;
}
// Compare individual items
oldInputs.forEach((oldInput, index) => {
const newInput = newInputs[index];
if(oldInput !== newInput) {
console.log(`${prefix} - The input changed in position ${index}`);
console.log("Old value:", oldInput)
console.log("New value:", newInput)
}
})
}
You could use this like this:
useEffectDebugger(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d], 'Effect Name')
And you would get output like:
Effect Name - The input changed in position 2
Old value: "Previous value"
New value: "New value"
There’s another stack overflow thread stating you can use useRef to see a previous value.
https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
The React beta docs suggest these steps:
Log your dependency array with console.log:
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
console.log([todos, tab]);
Right-click on the arrays from different re-renders in the console and select “Store as a global variable” for both of them. It may be important not to compare two sequential ones if you are in strict mode, I'm not sure.
Compare each of the dependencies:
Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays?
This question was answered with several good and working answers, but I just didn't like the DX of any of them.
so I wrote a library which logs the dependencies that changed in the easiest way to use + added a function to log a deep comparison between 2 objects, so you can know what exactly changed inside your object.
I called it: react-what-changed
The readme has all of the examples you need.
The usage is very straight forward:
npm install react-what-changed --save-dev
import { reactWhatChanged as RWC } from 'react-what-changed';
function MyComponent(props) {
useEffect(() => {
someLogic();
}, RWC([somePrimitive, someArray, someObject]));
}
In this package you will also find 2 useful functions for printing deep comparison (diffs only) between objects. for example:
import { reactWhatDiff as RWD } from 'react-what-changed';
function MyComponent(props) {
useEffect(() => {
someLogic();
}, [somePrimitive, someArray, someObject]);
RWD(someArray);
}

How to use insert() in sequelize migration?

I want to create only one row using insert() in Sequelize migration. I have seen the examples for bulkInsert() but don't want to use bulk.
We have this function to create only one row:
insert(instance, tableName, values, options)
But I don't understand what's the instance here in param?
I am using bulkInsert because it does not ask for instance param.
It will be great if you can add insert in my code written below.
Migration lib: https://github.com/sequelize/sequelize/blob/master/lib/query-interface.js
//Code for insertion using bulkInsert
module.exports = {
up: queryInterface => {
queryInterface.describeTable("Platforms").then(attributes => {
return queryInterface.bulkInsert("Platforms", [
{
id: 6,
display_name: "Booking.com",
code: "booking.com"
}
]);
});
},
down: queryInterface => {
return queryInterface.bulkDelete("Platforms", {
id: 6
});
}
};
import Platform from '../models/Platform';
module.exports = {
up: queryInterface => {
queryInterface.describeTable("Platforms").then(attributes => {
return queryInterface.insert(Platform, "Platforms", [
{
id: 6,
display_name: "Booking.com",
code: "booking.com"
}
]);
});
},
down: queryInterface => {
return queryInterface.bulkDelete("Platforms", {
id: 6
});
}
};
Instance here is for model instance that you define using sequilize.

Categories

Resources