How to test Svelte component props with Vitest? - unit-testing

I want to test the props of a Svelte component with Vitest.
Component:
<script>
export let foo
</script>
<div>{foo}</div>
Test:
const { component } = render(MyComponent, { foo: 'bar' })
expect(component.foo).toBe('bar')
When I run this test, I get the following error:
Props cannot be read directly from the component instance
unless compiling with 'accessors: true' or '<svelte:options accessors/>'
According to this post, I should pass accessors: true to the render() function:
const { component } = render(MyComponent, { accessors: true })
However, this doesn't work either and I keep getting the same error.
How can I test Svelte component props?

Related

redux-observable unit test epci with dependencies

I have an epic with the following signature (note the dependency)
export const incrementalSearchEpic = (action$, store, { incrementalSearchService }) => {
// eslint-disable-next-line max-len
return action$.ofType('SEARCH_STORES').mergeMap((action) =>
incrementalSearchService.performIncrementalSearch(action)
);
};
Now I need to unit test this and this is my unit testing code
beforeEach(() => {
epicMiddleWare = createEpicMiddleware(incrementalSearchEpic,
{
dependencies: {
incrementalSearchService: IncrementalSearchServiceMock
}
});
const mockStore = configureMockStore([epicMiddleWare]);
const getState = {}; // initial state of the store
store = mockStore(getState);
});
// eslint-disable-next-line max-len
it('calls the incrementalSearchService->performIncrementalSearch with the parameters when called', () => {
//dispatch the incremental search action
const searchStore = {
type: 'SEARCH_STORES',
SearchText: 'Aldi'
};
store.dispatch(searchStore);
expect(store.getActions()).toEqual([
searchStore
]);
});
However when I run the code I get the following error
TypeError: Cannot read property 'performIncrementalSearch' of undefined
Seems like the dependency does not get passed in properly.
I just realized: if redux-observable wasn't injecting the provided dependencies object you'd actually get Cannot read property 'incrementalSearchService' of undefined not performIncrementalSearch because redux-observable does not inject an object by default--it's not erroring because it is indeed passing your object.
Instead, the likely problem is that your import or definition of IncrementalSearchServiceMock is actually undefined. Perhaps a wrong named import or similar.
If you can't immediately see why, pause your debugger at the beginning of beforeEach and confirm the value of IncrementalSearchServiceMock is not undefined.

Angular2 - Call function from a tested component

I'm currently writing unit tests for Angular2 with Karma and Jasmine, but I'm pretty new in the unit testing and I'm facing some difficulties. When it comes to testing hardcoded properties or properties that don't involve async functions, it's all okay, but I need to be able to call the component's functions in order for some variables to get their values. What I'm doing is the following:
My component:
export class LoginComponent implements OnInit {
formLoginId: string;
loginUrl: string;
email: string;
password: string;
constructor(private googleAuthService: GoogleAuthService,
private authService: AuthenticationService,
private validationService: ValidationService,
private router: Router,
private titleService: Title) {
this.titleService.setTitle("Login");
this.formLoginId = "#form-login";
}
ngOnInit() {
this.googleAuthService.getLink((response) => {
this.loginUrl= response.json().url;
});
}
login() {
if (this.validationService.isValid(this.formLoginId)) {
this.authService.login(this.email, this.password);
}
}
Now I want to write a unit test which can check if the loginUrl has taken any value. My test is bellow:
describe('Login Component', ()=> {
let component:LoginComponent;
let fixture:any;
beforeEach(async(()=> {
TestBed.configureTestingModule({
//declarations,imports and providers
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
}); /some-other-tests/
it('should have login url', fakeAsync(()=> {
component.ngOnInit();
tick(1000);
expect(component.loginUrl).toBeDefined();
}));
});
But it seems that its not working. I'm still getting undefined for the mentioned variable. How can I call a method from a component and check the variables after its result?
Thanks!
In this case, you need to mock the GoogleAuthService to return with some information, as otherwise that getLink never resolves.
You can specify a mock provider for the GoogleAuthService and have it return an observable that's already resolved.

How to unit test an ember controller

I have a single action defined in an ember controller that calls 2 separate functions that are part of the controller. I'd like to mock out those functions in a unit test in order to confirm if the action method called the correct function.
My controller looks like this:
export default Ember.Controller.extend({
functionA() {
return;
},
functionB() {
return;
},
actions: {
actionMethod(param) {
if(param) {
return this.functionA();
}
else {
return this.functionB();
}
}
}
});
In practice, the controller works, however in the unit test, functionA and functionB are both undefined. I tried to log this to the console, but can't find where functionA and functionB are, so I'm unable to properly mock them. I expected them to be in the top level of the object next to actions, but instead I only found _actions with actionMethod properly defined.
My unit test looks like below
const functionA = function() { return; }
const functionB = function() { return; }
test('it can do something', function(assert) {
let controller = this.subject();
// I don't want the real functions to run
controller.set('functionA', functionA);
controller.set('functionB', functionB);
controller.send('actionMethod', '');
// raises TypeError: this.functionA is not a function
// this doesn't work etiher
// controller.functionB = functionB;
// controller.functionA = functionA;
// controller.actions.actionMethod();
}
Does anyone have any ideas on how I can replace those functions in the testing environment? Or perhaps, is there a better way to test this functionality or set up my controller?
edit
typo: this.subject to this.subject()
To replace the functions of the controller in the unit test, you can pass parameter to the this.subject() function:
let controller = this.subject({
functionA(){
//this function overriddes functionA
},
functionB(){
//this function overriddes functionB
},
});
Look at the sample twiddle.
This method is especially useful for replacing the injected service of the controllers.
Introduce corresponding property you are dealing with, let us say name property,
So your controllers would be looking like this,
import Ember from 'ember';
export default Ember.Controller.extend({
name:'',
functionA() {
this.set('name','A');
},
functionB() {
this.set('name','B');
},
actions: {
actionMethod(param) {
if(param) {
return this.functionA();
}
else {
return this.functionB();
}
}
}
});
And you can test for the name property value after calling actionMethod.
test(" testing functionA has been called or not", function(assert){
let controller = this.subject();
controller.send('actionMethod',true);
//If you would like to call functionA just say controller.functionA()
assert.strictEqual(controller.get('name'),'A',' name property has A if actionMethod arguments true');
controller.send('actionMethod',false);
assert.strictEqual(controller.get('name'),'B',' name property has B actionMethod arguments false');
});

Does Enzyme test utility work with React.createClass?

Most of the component in my react+meteor app use the React.createClass api.
When I try to use render any of them in the test file using render or mount, it throws the following error:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Constructor`.
at invariant (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:23890:15)
at ReactCompositeComponentWrapper.instantiateReactComponent [as _instantiateReactComponent] (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:14982:134)
at ReactCompositeComponentWrapper.performInitialMount (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15407:22)
at ReactCompositeComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15298:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at ReactCompositeComponentWrapper.performInitialMount (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15411:34)
at ReactCompositeComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15298:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at mountComponentIntoNode (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:20348:32)
at ReactReconcileTransaction.perform (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:9090:20)
Also, using shallow throws this error:
TypeError: Component is not a function
at packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15346:16
at measureLifeCyclePerf (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15115:12)
at ShallowComponentWrapper._constructComponentWithoutOwner (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15345:14)
at ShallowComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15228:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at ReactShallowRenderer._render (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21853:21)
at _batchedRender (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21834:12)
at Object.batchedUpdates (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:17599:7)
at Object.batchedUpdates (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:7770:20)
at ReactShallowRenderer.render (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21827:16)
But if I render a component create using the React.Component api, it works perfectly fine.
Now, my question is, does enzyme support the older React.createClass api?
Enzyme is fine with React.createClass. See the test case below taken from one of Enzyme tests.
https://github.com/airbnb/enzyme/blob/master/test/ShallowWrapper-spec.jsx#L13
it('can pass in context', () => {
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
});

error: No provider for #Attribute('sampleString')

We are trying to write unit test for a component which uses a third party java script library. The constructor of our component looks like -
#Constructor(#Inject(ElementRef) private eleref:ElementRef, #Attribute('sampleString') private sampleString: string)
We use that attribute to pass it to my third party library. And in there it does a specific task based on that attribute. If I don't pass it, it means simply ignore it and do regular stuff.
When we try to use/inject this component in our test class, it gives us error.
Error: DI Exception: No Provider for #Attribute('sampleString')!
Can someone suggest for what would be the provider for this? If your example can elaborate why this error and how to solve such issues in general, that will be bonus.
//component
#component({selector: 'mytable', templateUrl:'URL of template'}
export class mycomp{
//data members
constructor (element ref injection, #Attribute('sample string') private sampleString:string){}
//public methods
private ngOninit(){ this.dataview = dataview of third party lib. }
}
//Test
Describe("my test",()=>{
beforeEachProviders(()=>[ mycomp, provider for elementRef]);
It('test', async(inject ([TestComponentBuilder,mycomp], (tcb: TestComponentBuilder) => {
tcb.createAsync(mycomp)
.then ((fixture)=> {
expect(true). toBe(false)
})
});
The attribute needs to be
#Attribute('sampleString')
instead of
#Attribute('sampleString')
You need a test component that wraps the component that you actually want to test to be able to pass the attribute:
#component({
selector: 'mytable',
templateUrl:'URL of template'
}
export class mycomp{
//data members
constructor (element ref injection, #Attribute('sampleString') private sampleString:string){}
//public methods
private ngOninit(){ this.dataview = dataview of third party lib. }
}
#component({
selector: 'test',
template:'<mytable sampleString="xxx"></mytable>'
}
export class TestComponent{
}
//Test
describe("my test",()=>{
beforeEachProviders(()=>[ mycomp, provider for elementRef]);
it('test', async(inject ([TestComponentBuilder,mycomp], (tcb: TestComponentBuilder) => {
tcb.createAsync(TestComponent)
.then ((fixture)=> {
expect(true). toBe(false)
// get the mycomp component from fixture ...
})
});