Aurelia inject mock dependency - javascript

I have this aurelia component for displaying a feed to the user which depends on a custom API service class called Api for fetching the feed. The Api class has a get() function which in turn uses HttpClient to fetch the data.
Trying to test the component I want to mock the service class, specifically the get function, to return suitable test data and have this mock injected into the component via aurelia's DI container. The DI part I am having trouble with.
Here is the relevant part of component's js file
import {bindable, inject} from 'aurelia-framework';
import {Api} from 'services/api';
#inject(Api)
export class Feed {
events = null;
constructor(api) {
console.info('feed.js constructor, api:', api)
this.api = api;
}
And the relevant code from my test
beforeEach(done => {
...
let mockApi = new Api();
spyOn(mockApi, 'get').and.returnValue(mockGetResponse);
const customConfig = (aurelia) => {
let conf = aurelia.use.standardConfiguration().instance("Api", mockApi);
console.info('Registering Api:', conf.container.get("Api"));
return conf;
}
const ct = new ComponentTester();
ct.configure = customConfig;
sut = ct.withResources('activityfeed/feed');
sut.inView('<feed username.bind="username"></feed>')
.boundTo({username: TEST_USER});
sut.create(bootstrap).then(() => {
done();
});
});
This code is actually working the way I intended as far as I can tell. On creation of the component my customConfig function is called and the mockApi instance is logged to the console.
However later in the bootstrapping process the component constructor still receives an instance of the actual Api service class instead of my mock instance which was registered to the container.
Spent the last couple of hours trying to dig up any documentation or examples for doing things like this without success so if anyone can assist I would greatly appreciate it.
Or if there is / are alternative ways to accomplish this that would work just as well.

When testing a standard component that consists of both a view and a view model, using the aurelia-testing package, I find that a cleaner approach might be to let Aurelia create both the view and view-model, and use mocked classes for all view model dependencies.
export class MockApi {
response = undefined;
get() { return Promise.resolve(this.response) }
}
describe("the feed component", () => {
let component;
let api = new MockApi();
beforeEach(() => {
api.response = null;
component = StageComponent
.withResources("feed/feed")
.inView("<feed></feed>");
component.bootstrap(aurelia => {
aurelia.use
.standardConfiguration();
aurelia.container.registerInstance(Api, api);
});
});
it("should work", done => {
api.response = "My response";
component.create(bootstrap).then(() => {
const element = document.querySelector("#selector");
expect(element.innerHTML).toBe("My response, or something");
done();
});
});
});
This approach lets you verify the rendered HTML using the normal view model class, mocking the dependencies to control the test data.

Just to answer my own question, at least partially, if it can be useful to someone.
By using the actual Api class constructor as the key instead of the string "Api" the mock seems to be correctly injected.
I.e.
import {Api} from 'services/api';
...
let conf = aurelia.use.standardConfiguration().instance(Api, mockApi);

Related

How to add custom request header to testcafe test suite?

I have a bunch of tests that I am running through testcafe. Now I need to add a custom request header for each test that uniquely identifies the call is originating from the testcafe suite and not a real user.
Is there a way to add the custom header to all the test cases at once?
I was looking at this but it seems like I would need to update each fixture to get this working. So, I wanted to know if there's a way I can set it on a top level file before calling the test suite?
EDIT:
So, this is what I am currently doing. I have created a new file that contains the class:
import { RequestHook } from 'testcafe';
class CustomHeader extends RequestHook {
constructor () {
// No URL filtering applied to this hook
// so it will be used for all requests.
super();
}
onRequest (e) {
e.requestOptions.headers['my_custom_variable'] = 'my_value';
}
onResponse (e) {
// This method must also be overridden,
// but you can leave it blank.
}
}
const customHeader = new CustomHeader();
export default customHeader;
And then in my each test file, update the fixtures to be like this:
import { customHeader } from 'customer_header'
fixture(`Test app avail`)
.page(appURL)
.requestHooks(customHeader)
.beforeEach(async() => {
await myTestfunction();
});
Does this make sense?
Currently there is no way to specify hooks on the test run level. But, if updating each fixture is not reasonable in your case, you can use the workaround posted in the discussion about this feature. In order to apply your request hook to each fixture in the test suite you'll need to change "setup.js" (from the workaround above) as follows:
export const fixture = (...args) => global.fixture(...args)
.requestHooks(customHeader)
.beforeEach(async t => {
console.log('each');
});

How do I pass a dependency to a Vue component?

I have a class that is intended to serve as a repository for making AJAX requests using axios:
export default class SomeRepository {
getEncryptedValue (value) {
return axios.get('http://localhost/api/v1/encrypt')
}
}
And I have a component that calls this repository's method inside the methods property in the component, like so:
<template>
...
</template>
<script>
import SomeRepository from '#/classes/SomeRepository'
export default {
data () {
return {
value: '',
result: ''
}
},
methods: {
encrypt () {
let someRepo = new SomeRepository()
someRepo.getEncryptedValue(this.value)
.then(response => {
this.result = response.data.result
})
}
}
}
</script>
How can I pass SomeRepository as a dependency? My goal is that I want to mock it in my unit tests.
I am looking for a straightforward solution, preferably one that does not involve third-party libraries or boilerplate.
I've tried also doing:
import Vue from 'vue'
import SomeRepository from '#/classes/SomeRepository'
Vue.use(SomeRepository)
// and
Vue.use(new SomeRepository())
which clearly don't work (honestly, I didn't expect them to). I also tried following this article https://codeburst.io/dependency-injection-with-vue-js-f6b44a0dae6d but I did not really like the approach of having to create a mixin every time I want to use a dependency.
I've also considered passing it as a prop, but was not sure where to instantiate the object before passing it.
There is a ton of ways to mock functions. The most simplistic that I have found is simply accepting dependencies as parameters of a function and replace the function to use in your tests.
Example of Method
// Function
function func(dependency) {
dependency.use()
}
// In App
func(dependency) // -> runs dependency.use
// In Tests
func(mockDependency) // -> runs mocked dependency.use
Your Example
Once you know this method you can do a ton of different versions of it but to show a super simple version.
encrypt() {
this._encrypt(SomeRepository)
}
_encrypt (SomeRepository) {
let someRepo = new SomeRepository()
someRepo.getEncryptedValue(this.value)
.then(response => {
this.result = response.data.result
})
}
You would test _encrypt with the mock dependency.
You can also do something like this.
encrypt (_SomeRepository=SomeRepository) {
let someRepo = new _SomeRepository()
someRepo.getEncryptedValue(this.value)
.then(response => {
this.result = response.data.result
})
}
If you pass in the mocked version it will use that if you do not it will use the real one.
The idea is to use this method however you see fit, but I think you get the idea. It is super simple no magic and no libraries needed.
You should use a Vue plugin
https://v2.vuejs.org/v2/guide/plugins.html
Then you can access it via e.g. this.$someDeps
For unit testing, you can mock it easily using Vue Test Utils https://vue-test-utils.vuejs.org/api/options.html#mocks

How to test rxjs ajax call with jest?

I have a container component where I'm fetching the data via ajax operator from rxjs
const data = ajax(someUrl).pipe(map(r => r.response));
And in my componentDidMount I have
data.subscribe((data) => {
this.setState({ data });
});
// test.js
import React from 'react';
import { mount } from 'enzyme';
import { ajax } from 'rxjs/ajax'
import App from '../src/App';
describe('<App />', () => {
const wrap = mount(<App />);
const data = [{ 1: 'a' }];
const mock = ajax('http://url.com').pipe(map(() => data));
it('renders', () => {
console.log(mock.subscribe(x => x));
expect(wrap.find(App).exists()).toBe(true);
});
});
How do I go about mocking the response so that when I run the test it I can pass that data on to other components and check if they render?
All the testing examples I've found have been redux-Observable ones which I'm not using.
Thanks a lot!
First you need to understand that you should be testing one thing at a time.
Meaning that testing your async method execution should be separated from testing your components rendering proper content.
To test async methods you can mock your data and than mock timers in Jest.
https://jestjs.io/docs/en/tutorial-async
https://jestjs.io/docs/en/asynchronous
https://jestjs.io/docs/en/timer-mocks.html
with jest.useFakeTimers() and techniques mentioned above.
For testing component proper rendering use jest snapshots and e2e testing (can be done with ex. TestCafe)
To connect those approaches you need to design you app in a way that will allow you to:
The API you call in your component, should be external to component and be called from that external source (different file, different class, however you design it), so you can replace it in test.
Whole API should be modular, so you can take one module and test it without initializing whole API just for this case.
If you design your app in such manner, you can initialize part of the API with mock data, than render your component in test and as it will call mocked API, you can check if it renders what you expect it to.

How to mock an asynchronous function call in another class

I have the following (simplified) React component.
class SalesView extends Component<{}, State> {
state: State = {
salesData: null
};
componentDidMount() {
this.fetchSalesData();
}
render() {
if (this.state.salesData) {
return <SalesChart salesData={this.state.salesData} />;
} else {
return <p>Loading</p>;
}
}
async fetchSalesData() {
let data = await new SalesService().fetchSalesData();
this.setState({ salesData: data });
}
}
When mounting, I fetch data from an API, which I have abstracted away in a class called SalesService. This class I want to mock, and for the method fetchSalesData I want to specify the return data (in a promise).
This is more or less how I want my test case to look like:
predefine test data
import SalesView
mock SalesService
setup mockSalesService to return a promise that returns the predefined test data when resolved
create the component
await
check snapshot
Testing the looks of SalesChart is not part of this question, I hope to solve that using Enzyme. I have been trying dozens of things to mock this asynchronous call, but I cannot seem to get this mocked properly. I have found the following examples of Jest mocking online, but they do not seem to cover this basic usage.
Hackernoon: Does not use asychronous calls
Wehkamp tech blog: Does not use asynchronous calls
Agatha Krzywda: Does not use asynchronous calls
GitConnected: Does not use a class with a function to mock
Jest tutorial An Async Example: Does not use a class with a function to mock
Jest tutorial Testing Asynchronous Code: Does not use a class with a function to mock
SO question 43749845: I can't connect the mock to the real implementation in this way
42638889: Is using dependency injection, I am not
46718663: Is not showing how the actual mock Class is implemented
My questions are:
How should the mock class look like?
Where should I place this mock class?
How should I import this mock class?
How do I tell that this mock class replaces the real class?
How do set up the mock implementation of a specific function of the mock class?
How do I wait in the test case for the promise to be resolved?
One example that I have that does not work is given below. The test runner crashes with the error throw err; and the last line in the stack trace is at process._tickCallback (internal/process/next_tick.js:188:7)
# __tests__/SalesView-test.js
import React from 'react';
import SalesView from '../SalesView';
jest.mock('../SalesService');
const salesServiceMock = require('../SalesService').default;
const weekTestData = [];
test('SalesView shows chart after SalesService returns data', async () => {
salesServiceMock.fetchSalesData.mockImplementation(() => {
console.log('Mock is called');
return new Promise((resolve) => {
process.nextTick(() => resolve(weekTestData));
});
});
const wrapper = await shallow(<SalesView/>);
expect(wrapper).toMatchSnapshot();
});
Sometimes, when a test is hard to write, it is trying to tell us that we have a design problem.
I think a small refactor could make things a lot easier - make SalesService a collaborator instead of an internal.
By that I mean, instead of calling new SalesService() inside your component, accept the sales service as a prop by the calling code. If you do that, then the calling code can also be your test, in which case all you need to do is mock the SalesService itself, and return whatever you want (using sinon or any other mocking library, or even just creating a hand rolled stub).
You could potentially abstract the new keyword away using a SalesService.create() method, then use jest.spyOn(object, methodName) to mock the implementation.
import SalesService from '../SalesService ';
test('SalesView shows chart after SalesService returns data', async () => {
const mockSalesService = {
fetchSalesData: jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => resolve(weekTestData));
});
})
};
const spy = jest.spyOn(SalesService, 'create').mockImplementation(() => mockSalesService);
const wrapper = await shallow(<SalesView />);
expect(wrapper).toMatchSnapshot();
expect(spy).toHaveBeenCalled();
expect(mockSalesService.fetchSalesData).toHaveBeenCalled();
spy.mockReset();
spy.mockRestore();
});
One "ugly" way I've used in the past is to do a sort of poor-man's dependency injection.
It's based on the fact that you might not really want to go about instantiating SalesService every time you need it, but rather you want to hold a single instance per application, which everybody uses. In my case, SalesService required some initial configuration which I didn't want to repeat every time.[1]
So what I did was have a services.ts file which looks like this:
/// In services.ts
let salesService: SalesService|null = null;
export function setSalesService(s: SalesService) {
salesService = s;
}
export function getSalesService() {
if(salesService == null) throw new Error('Bad stuff');
return salesService;
}
Then, in my application's index.tsx or some similar place I'd have:
/// In index.tsx
// initialize stuff
const salesService = new SalesService(/* initialization parameters */)
services.setSalesService(salesService);
// other initialization, including calls to React.render etc.
In the components you can then just use getSalesService to get a reference to the one SalesService instance per application.
When it comes time to test, you just need to do some setup in your mocha (or whatever) before or beforeEach handlers to call setSalesService with a mock object.
Now, ideally, you'd want to pass in SalesService as a prop to your component, because it is an input to it, and by using getSalesService you're hiding this dependency and possibly causing you grief down the road. But if you need it in a very nested component, or if you're using a router or somesuch, it's becomes quite unwieldy to pass it as a prop.
You might also get away with using something like context, to keep everything inside React as it were.
The "ideal" solution for this would be something like dependency injection, but that's not an option with React AFAIK.
[1] It can also help in providing a single point for serializing remote-service calls, which might be needed at some point.

Angular 2 transfer ajax call response to another component

I just started playing with angular 2 and i've ran into a small problem, that i ve searched for in various forms and also angulars documentation.
I've managed to make a service that makes a call and then i want in a component when i press a button to load another component with dynamicload component and have access to the ajax result.
The problem is that I can t figure out how to do that..
The question is how can I make the result accesible in other components using Observables or Promises method.
If I understood correctly your question, you are looking a way to insert a data from request to another nested component.
I hope this image will clarify for you the data flow for this case.
Your Root component is calling a service method which returns for you promise object.
Then you map needed data from response to the component model inside Root Component constructor.
And your Child component should be subscribed for the model which you was preparing in previous step.
ngOnInit() {
this.dataService.getSomeData()
.subscribe((data: IData) => {
this.data = data;
});
}
Just a short example above how to set model in the root component from the promise object to the local model.
New research:
There is another way to fill your components by data from api's. You can use EventEmitter to emit event from service, and then, you can subscribe for this event inside you created components, so they will get a data, each time there will be called the service. Here is nice example of this strategy in the first answer. Service Events
Hope it will help you, let me know if you will need additional info!
Just create a service, then inject the service where you want.
Here it's an example how to share a service ajax data across many components without making the request twice :
https://stackoverflow.com/a/36413003/2681823
the Service:
#Injectable()
export class DataService {
constructor(private http: Http) { }
private _dataObs = new ReplaySubject<request>(1);
getData(forceRefresh?: boolean) {
// On Error the Subject will be Stoped and Unsubscribed, if so, create another one
this._dataObs = this._dataObs.isUnsubscribed ? new ReplaySubject(1) : this._dataObs;
// If the Subject was NOT subscribed before OR if forceRefresh is requested
if (!this._dataObs.observers.length || forceRefresh) {
this.http.get('http://jsonplaceholder.typicode.com/posts/2')
.subscribe(
requestData => {
this._dataObs.next(requestData);
},
error => this._dataObs.error(error));
}
return this._dataObs;
}
}
the Component:
#Component({
selector: 'child',
template : `<button (click)="makeRequest()" class="btn">Click me!</button>`
})
export class Child {
constructor(private _dataService: DataService) { }
makeRequest() {
this._dataService.getData().subscribe(
requestData => {
console.log('ChildComponent', requestData);
}
}
}
A full working example/plunker can be found here : http://plnkr.co/edit/TR7cAqNATuygDAfj4wno?p=preview

Categories

Resources