I am using jest for testing and I have a lambda function in my Stack I want to test.
Like this:
const lambda = new lambda.Function(this, "MyLambda", {
...
code: lambda.Code.fromAsset("../assets/lambda.zip"),
...
}
);
I want to test some of the properties but also if the lambda is in the stack. But when I run the test it complains that my lambda.zip doesn't exist. Which is fair enough, as it's built as part of the another build job.
Is there any way to inject or somehow mock the lambda's asset.
You can try using Code.fromInline() as it doesn't require any files on disk. Simply pass a dummy function code as a string.
lambda.Code.fromInline("exports.handler = async function(event, context) {}")
Based on kichik's idea to use Code.fromInline(), this worked for me:
import { InlineCode } from "#aws-cdk/aws-lambda"
jest.mock("#aws-cdk/aws-lambda", () => ({
...jest.requireActual("#aws-cdk/aws-lambda"),
Code: {
fromAsset: () => new InlineCode("foo"),
},
}))
Probably can be simplified with jest.spyOn, but I couldn't figure out how to make it work.
In a lot of simple scenarios, there's no need to bother with a complicated jest mocking.
beforeAll(() => {
Object.defineProperty(Code, 'fromAsset', {
value: () => Code.fromInline('test code'),
});
});
Related
Rather than create a massive E2E test, I want to verify what the useMutation is receiving from the component. There is a lot of business logic before my component "posts" and I want to test that the GraphQL mutation function is receiving the shape of data.
Manually mocking the query doesn't provide value in this case, as it skips the business logic I want to keep track of. There is no value right now to let the query return full data & response, as my component will unmount and URL will change after successful data is returned.
So ideally, we just stop the test when the useMutation hook is called.
I am hoping to do something like:
const mutationSpy = jest.spyOn(graphQL, 'useMutation');
...
expect(mutationSpy).toHaveBeenCalledWith(myDataShape);
The best way to track whether a mutation has been called is to use the MockedProvider from #apollo/react-testing (react-native) or #apollo/client (react) to supply a callback function to your mock response that changes a variable in the test scope so that it may be checked once the test has been run. Something like this.
Here is the documentation:
https://www.apollographql.com/docs/react/development-testing/testing/#testing-mutation-components
test.js
let createMutationCalled = false
const mocks = [
{
request,
result: () => {
createMutationCalled = true
return { data }
}
}
];
describe('test', () => {
test('should call createTicket mutation', async () => {
const { getByTestId } = render(
<MockedProvider mocks={mocks}>
<SelfReportPage />
</MockedProvider>
)
let input = getByTestId('sr-description')
let submit = getByTestId('sr-submit')
fireEvent.changeText(input, 'Test text.')
fireEvent.press(submit)
await new Promise(r => setTimeout(r, 0));
expect(createMutationCalled).toBe(true)
})
})
Trying run a test case for the following:
async getParents() {
const { user, services, FirmId } = this.props;
let types = await Models.getAccounts({ user, services, firmId: FirmId });
let temp = types.map((type) => {
if(this.state.Parent_UID && this.state.Parent_UID.value === type.Account_UID) {
this.setState({Parent_UID: {label: type.AccountName, value: type.Account_UID}})
}
return {
label: type.AccountName,
value: type.Account_UID,
}
})
this.setState({ParentOptions: temp});
}
here is what i have so far for my test:
beforeEach(() => wrapper = mount(<MemoryRouter keyLength={0}><AccountForm {...baseProps} /></MemoryRouter>));
it('Test getParents function ',async() => {
wrapper.setProps({
user:{},
services:[],
FirmId:{},
})
wrapper.find('AccountForm').setState({
SourceOptions:[[]],
Parent_UID: [{
label:[],
value:[],
}],
});
wrapper.update();
await
expect(wrapper.find('AccountForm').instance().getParents()).toBeDefined()
});
If i try to make this ToEqual() it expects a promise and not anobject, what else could I add into this test to work properly.
Goal: Make sure the functions gets called correctly. The test is passing at the moment and has a slight increase on test coverage.
Using Jest and Enzyme for React Js
you can put the await before the async method, like:
await wrapper.find('AccountForm').instance().getParents()
and compare if the state was changed.
In another way, if can mock your API request, because this is a test, then you do not need the correct API, but know if the function calls the API correctly and if the return handling is correct.
And, you cand spy the function like:
const spy = jest.spyOn(wrapper.find('AccountForm').instance(), 'getParents');
and campare if the function was called if they are triggered by some action:
expect(spy).toBeCalled()
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);
});
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');
});
});
I'm trying to test my asyn thunk middleware function using mocha, chai and sinon (my first time!).
Please consider my files:
ayncActionCreators.js
export const fetchCurrentUser = () => {
return (dispatch) => {
setTimeout(dispatch, 100);
}
};
ayncActionCreators.spec.js
//...
it('Should work', () => {
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch);
expect(dispatch.called).to.be.true;
});
I did not yet implement the fetchCurrentUser function - just assumed it will take some "server" time and then it will call 'dispatch()'.
The spec fails, due to the async flow. If I add a setTimeout of 101 ms before the expect - it passes.
My code will use some DB API that returns promise, so the async function will eventually look like:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
So I tried to require dbAPI and create a sinon.stub().returns(Promise.resolve()) inside the test and it didn't work as well (I thought that since the stub returns a resolved promise - the async function will act like a synchronous function).
Any ideas how should I test async functions like that?
Thank,
Amit.
Don't mock dispatch with sinon, write your own and call Mocha's done() in that when it's done.
it('Should work', (done) => {
const dispatch = () => {
// Do your tests here
done();
};
const action = fetchCurrentUser();
action(dispatch)
// Also allow quick failures if your promise fails
.catch(done);
})
If you're just wanting to ensure that the dispatch is called, then mocha will time out. The catch on the returned promise from your async action creator allows errors to be shown in the right place and for the test to fail rather than time out.
Well, I think I've found a solution:
Assuming my async function looks like this:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
Then I can write the spec as follows:
it('Should work', () => {
dbAPI.fetchUser = sinon.stub().returns(Promise.resolve({username: 'John'}));
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch).then(() => {
expect(dispatch.called).to.be.true;
});
});
I don't know if this is a workaround or not, but it works. I would appreciate your opinions of a better way of doing this...
Thanks,
Amit.