How to wrap an object into a function return this object using jscodeshift - jscodeshift

Let's say I have the following file
export default {
foo: 'bar'
}
How can I transform this file using jscodeshift so it wraps the object into function like this:
export default () => ({
foo: 'bar'
})
My main problem is how to use the api.jscodeshift.arrowFunctionExpression(), especially how to create the function body. Cause I think all I need to do, is to replace the ObjectExpression with a function that has the ObjectExpression as its body.

Another option is to use j.template.expression which is a tagged template that lets you interpolate JavaScript with existing nodes:
Complete example:
return j(file.source)
.find(j.ExportDefaultDeclaration)
.find(j.ObjectExpression)
.replaceWith(
path => j.template.expression`theme => ${path.node}`
)
.toSource();

Found out by myself. arrowFunctionExpression take a list params and then a blockStatement. This will generate the function:
const fn = j.arrowFunctionExpression(
[{ type: "Identifier", name: "theme" }],
j.blockStatement([j.returnStatement(stylesObject)])
);
Then create a new exportDefaultDeclaration and pass the function to it.
const e = j.exportDefaultDeclaration(fn)
return j(e).toSource();

Related

Cypress multiple arrow function parameters?

So I'm just starting to learn Typescript with Cypress and I noticed this in a page I was reading about here: https://medium.com/#NicholasBoll/cypress-io-scaling-e2e-testing-with-custom-commands-6b72b902aab
export const updateTodo = (name: string) => ($todo: JQuery) => {
cy.wrap($todo).within(() => {
cy.get('label').dblclick()
cy.get('.edit').clear().type(`${name}{enter}`)
})
So I'm still new to typescript and I understand I think that the Jquery element is the subject parameter although I'm still a little bit unsure at what would represent a "Jquery" element/parameter in Cypress.
However what confused me is the fact that there are two fat arrow parameter sections... I've not seen that before? What exactly does that mean? Especially when further down it's called as such (With just a string):
it('should update a todo', () => {
createTodo('Learn Cypress Command API')
.then(updateTodo('Learn Cypress composition'))
.then(getTodoName)
.should('equal', 'Learn Cypress composition')
})
Can anyone explain what's going on here?
Two fat arrows just means the function is returning another function.
So
export const updateTodo = (name: string) => ($todo: JQuery) => {
cy.wrap($todo).within(() => {
cy.get('label').dblclick()
cy.get('.edit').clear().type(`${name}{enter}`)
})
is equivalent to
export const updateTodo = (name: string) => { // outer function
return ($todo: JQuery) => { // inner function
cy.wrap($todo).within(() => {
cy.get('label').dblclick()
cy.get('.edit').clear().type(`${name}{enter}`)
})
Where you use the double-fat-arrow function is another shorthand,
This
.then(updateTodo('Learn Cypress composition'))
is shorthand for this
.then((name: string) => updateTodo(name)('Learn Cypress composition'))
where the double brackets updateTodo()() calls the outer function then the inner function.
Or even longer syntax:
.then((name: string) => {
const innerFn = updateTodo(name);
return innerFn('Learn Cypress composition');
})

React Query queryClient.setQueryData isn't updating the cached data

I have a custom hook that looks something like this:
import { useQuery, useQueryClient } from 'react-query'
import { get } from '#/util/api' // Custom API utility
import produce from 'immer' // Using immer for deep object mutation
export function useData() {
const queryClient = useQueryClient()
const { data, isSuccess } = useQuery(
'myData', () => get('data')
)
function addData(moreData) {
const updatedData = produce(data.results, (draft) => {
draft.push(moreData)
})
setData(updatedData)
}
function setData(newData) {
queryClient.setQueryData('myData', newData)
}
return {
data: data && data.results,
setData,
addData,
}
}
My data in data.results is an array of objects. When I call addData it creates a copy of my current data, mutates it, then calls setData where queryClient.setQueryData is called with a new array of objects passed in as my second argument. But my cached data either doesn't update or becomes undefined in the component hooked up to the useData() hook. Does anyone know what I'm doing wrong?
code looks good from react-query perspective, but I'm not sure if that's how immer works. I think with your code, you will get back the same data instance with just a new data.results object on it. I would do:
const updatedData = produce(data, (draft) => {
draft.results.push(moreData)
})

using arrow function into the return block of page.evaluate of puppeter script

It probably is a matter of Promise:
Look at the since field of my return block,
using an arrow function it doesn't return any result:
{
link: 'www.xxxxxx.com/1234',
name: 'jhon doe',
since: {}
},
instead to return directly the value, it works as expected!
Since i need to perform complex operations with selectors, I'd like to use an inline arrow function in that point, how can I fix to get the result out?
let rawMembers = await page.evaluate(() => new Promise((resolve) => {
....
//captute all the link
const anchors = Array.from(document.querySelectorAll('a'));
let result = anchors.map(x => {
return {
link: x.getAttribute("href"),
name: x.innerText,
//since : x.parentNode.parentNode.parentNode.parentNode.getAttribute("class") <--- this works
since: x => { <---using an arrow function, it returns and empty objecy `{}`
// i need a function here to do complex and multiline operations
return x.parentNode.parentNode.parentNode.parentNode.getAttribute("class");
}
....
resolve(results);
i've tried this as well but with the same result
since: x => new Promise((resolve) => {
// i need a function here to do complex and multiline operations
resolve(x.parentNode.parentNode.parentNode.parentNode.getAttribute("class"));
})
In since you have a reference to the arrow function itself, not to its result. Functions are not serialaizable, so you get an empty object. You need to call the function, i.e. to use IIFE:
since: (() => {
return x.parentNode.parentNode.parentNode.parentNode.getAttribute("class");
})()

Pass data from one step to the next synchronously

Running Cypress 3.1.1 with cypress-cucumber-preprocessor 1.5.1. I need to pass some static data from one step to another (in the same scenario/test). I can do this using an alias, like this:
cy.wrap(someString).as('myString'), but then I have to access it asynchronously:
cy.get('#myString').then(myString => ...)
This is rather cumbersome, particularly when I have to pass multiple values, requiring multiple wrapped closures, for no apparent benefit. (Currently I'm working around this by aliasing an object, but I shouldn't need to do this.)
How can I pass primitive values from one step to another synchronously?
I thought I might be able to simply set this.myString='' to set the value on the Mocha shared context object, but in that case, the property exists but is set to undefined when accessed in later steps.
Even creating my own context variable with let outside of the step definition does not work. Is this simply a limitation of Cypress and/or the cypress-cucumber-preprocessor?
I managed to get it working the following way:
Add 2 tasks to the /plugins/index.js
const testStore = {}
module.exports = (on, config) => {
on('task', {
pushValue({ name, value }) {
console.log(name, value)
testStore[name] = value
console.log(testStore)
return true
},
})
on('task', {
getValue(name) {
return testStore[name]
},
})
Then you can add a variable in any test and reach it in any other place:
it('test', ()=>{
cy.task('pushValue', { name: 'orderNumber', value: orderNumber })
})
it('test 2', ()=>{
cy.task('getValue', 'orderNumber').then((order) => {
cy.visit(`/bookings/${order}`)
})
})
Here is a slightly more complicated (and not fully tested) method. A custom command can be added to save values to a global object.
In the Cypress test runner, all the tests seem to run sequentially, but you may have to be careful if using CI and parallel execution.
In /support/commands.js
export const testStore = {}
Cypress.Commands.add('saveAs', { prevSubject: true }, (value, propName) => {
console.log('saveAs', value, propName)
testStore[propName] = value;
return value;
})
In myTest.spec.js
import { testStore } from '../support/commands.js'
...
it('should have a title', () => {
cy.title()
.saveAs('title') // save for next test
.should('contain', 'myTitle) // this test's expectation
});
it('should test something else', () => {
cy.get('.myElement').contains(testStore.title);
});

How can I check in a jest test if a thunk action within a thunk action creator has been dispatched?

Here's a generalized example:
// myActions.js
export const actionOne = () => (dispatch) => {
dispatch(actionTwo());
};
export const actionTwo = () => ({
type: 'SOME_TYPE',
});
I would like to test that actionTwo has been either called or dispatched, ideally without the test knowing anything about what is going on in actionTwo, because I have a different test that takes care of that.
I am using redux-mock-store to dispatch the tested action to a mocked store and calling store.getActions() to find out if the expected actions within the thunk action creator have been dispatched. I feel it is not the right way to go in this particular scenario because then the test would test more than it should. I really only want to know if actionTwo has been called at all.
I'm aware of spyOn and jest.mock, but I've been unable to use either to solve my problem. Here's what the generalized test looks like:
// myActions.test.js
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from 'myActions';
const mockStore = configureMockStore([thunk]);
test('actionOne', () => {
const store = mockStore();
return store.dispatch(actions.actionOne()).then(() => {
// TODO: check if actions.actionTwo was called
});
});
test('actionTwo', () => {
const store = mockStore();
return store.dispatch(actions.actionTwo()).then(() => {
expect(store.getActions()).toEqual([{ type: 'SOME_TYPE' }]);
});
});
I'm grateful for any suggestions!
Took me a while, but I figured it out. It's not ideal (because it involves a small change to the tested code), but the closest to ideal that I could get.
// myActions.js
export const actionOne = () => (dispatch) => {
dispatch(exports.actionTwo());
};
export const actionTwo = () => ({
type: 'SOME_TYPE',
});
The important change is the exports.actionTwo(). That way, I make sure that I can overwrite the function's implementation from the outside (the test file) and the overwriting function will actually be called from within the imported file.
Now I can simply add something like the following to my test file:
beforeEach(() => {
actions.actionTwo = jest.fn(() => () => Promise.resolve());
});
actionTwo is now being mocked and I can use toBeCalledWith and other expectations on it. If I wish to test its actual implementation within the same test file, I can store it in a variable before calling beforeEach, like:
const actionTwo = actions.actionTwo;
And then in the test setup for its implementation, I can overwrite the mock calling
actions.actionTwo = actionTwo;
That's it. Now I can make sure to ignore all side effects from an exported function and test it as an actual unit.
It would be better to assert that two redux actions hit the store, not that actionOne calls the action creator.
Since all actions dispatched to the store must have an action type. Just make assertions about store.getActions():
test('actionOne', () => {
const store = mockStore();
return store.dispatch(actions.actionOne()).then(() => {
expect(store.getActions()).to.have.length(2);
expect(store.getActions()[0].type).to.equal('ACTION_ONE_TYPE');
// make additional assertions about the first action
expect(store.getActions()[1].type).to.equal('ACTION_TWO_TYPE');
});
});

Resources