This is my class component:
export class GoalSettingsPage {
public goal: Goal;
dismiss() {
this.viewCtrl.dismiss();
}
}
This is my test:
it('should emit on click', () => {
let g = new Goal()
let settingModal = Modal.create(GoalSettingsPage, { g:Goal });
settingModal.subscribe(hc => {
console.log(hc);
expect(hc).toEqual({hasCompleted:true});
});
settingModal.dismiss()
})
This is my error:
04 07 2016 16:36:48.438:ERROR [Chrome 51.0.2704 (Mac OS X 10.11.3) | Goal Settings | should emit on click]: TypeError: Cannot read property 'remove' of undefined
at Modal.ViewController.dismiss (http://localhost:9876/absolute/var/folders/zb/tpysrhsx7hbg1dnsn4gwtqq00000gn/T/65a6294f711f882f7429da26bc12e438.browserify?2c82fe582a9911b998cb77bce54ea6804460d5cd:59060:25)
Any idea what I am doing wrong?
Related
I have a small issue with a unit test I wrote for a controller method.
Short version:
return this.userPreferencesService.createPreferences(eUserId, userPreferences);
Long version:
I get this error:
UserPreferencesController › createUserPreferences › should create a new userPreferences
TypeError: this.userPreferencesService.createPreferences is not a function
31 | userPreferences: TestUserPreferencesDto,
32 | ): Promise<UserPreferences> {
> 33 | return this.userPreferencesService.createPreferences(eUserId, userPreferences);
| ^
34 | }
35 |
36 | /**
at UserPreferencesController.createPreferences (user-preferences/user-preferences.controller.ts:33:44)
at Object.<anonymous> (user-preferences/user-preferences.controller.spec.ts:67:45)
The toBeDefined passes but the createUserPreferences fails for the error above.
The code works great and there only the test fails.
I just can't find the reason this is not a function?
service file content (relevant data only):
#Injectable()
export class UserPreferencesService {
constructor(#InjectModel('UserPreferences') private userPreferencesModel: Model<UserPreferences>) {
}
/**
* ADD a single user preferences by id => POST api/v1/user-preferences/
* #param userPreferences
*/
async createPreferences(eUserId: string, userPreferences: TestUserPreferencesDto): Promise<UserPreferences> {
Object.assign(userPreferences, {eUserId: eUserId});
return this.userPreferencesModel.create(userPreferences);
}
This is the controller (relevant data only)
#Controller('v1/user-preferences')
export class UserPreferencesController {
constructor(private userPreferencesService: UserPreferencesService) {}
/**
* Add user preferences to the database
* #param userPreferences
*/
#Post()
async createPreferences(
#Headers('x-e-user-id') eUserId: string,
#Body()
userPreferences: TestUserPreferencesDto,
): Promise<UserPreferences> {
return this.userPreferencesService.createPreferences(eUserId, userPreferences);
}
This is the entire test file:
import {Test, TestingModule} from '#nestjs/testing';
import { getModelToken } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import {UserPreferencesController} from './user-preferences.controller';
import {UserPreferencesService} from './user-preferences.service';
import { exitToOptions } from './schemas/user-preferences.schema';
const ReturnedUserPreferencesMock = {
_id: '62a161a9654a511b28e6f3db',
eUserId: '123456',
uiTheme: 'dark',
panelWidth: 300,
editingHandles: true,
enableLightboxInEditor: true,
hiddenElements: true,
defaultDeviceView: 'mobile',
exitTo: exitToOptions.DASHBOARD,
};
const eUserIdeMock = '123456';
const userPreferencesMock = {
uiTheme: 'dark',
panelWidth: 327,
editingHandles: true,
enableLightboxInEditor: true,
hiddenElements: true,
defaultDeviceView: 'mobile',
exitTo: exitToOptions.DASHBOARD,
}
const mockUserPreferencesService = {
create: jest.fn().mockResolvedValueOnce(ReturnedUserPreferencesMock),
}
describe('UserPreferencesController', () => {
let controller: UserPreferencesController;
let service: UserPreferencesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UserPreferencesController],
providers: [{
provide: UserPreferencesService,
useValue: mockUserPreferencesService
}]
}).compile();
controller = module.get<UserPreferencesController>(UserPreferencesController);
service = module.get<UserPreferencesService>(UserPreferencesService);
});
it('Controler should be defined', () => {
expect(controller).toBeDefined();
});
describe('createUserPreferences', () => {
it('should create a new userPreferences', async () => {
const result = await controller.createPreferences(eUserIdeMock, userPreferencesMock);
expect(service.createPreferences).toHaveBeenCalledWith(eUserIdeMock, userPreferencesMock);
expect(result).toEqual(ReturnedUserPreferencesMock);
});
});
});
The mockUserPreferencesService you provide does not have a createPreferences method, only a create. You need to provide an implementation for each method you are going to call of the original service for your mock.
const mockUserPreferencesService = {
create: jest.fn().mockResolvedValueOnce(ReturnedUserPreferencesMock),
createPreferences: jest.fn().mockResolvedValueOnce(WhateverObjectShouldGoHere),
}
I'm getting an issue when writing test cases for my controller in AngularJs.
Reason I have found : When i initialize the moment in my constructor I'm getting this error while running the test cases.
I'm sharing my controller code as well as test file.
class contractCancellationCtrl {
constructor(
moment) {
'ngInject';
this.moment = moment;
this.minSalesDate = moment().subtract(1, 'months').date(1);
}
define(['contract'], () => {
'use strict';
let momentMock,
ctrl,
$q,
$scope;
const dateMock = "Feb 16, 2018 10:22 AM";
fdescribe('contractCancellation', () => {
beforeEach(() => {
module('nse.contract');
momentMock = jasmine.createSpyObj('moment', ['subtract']);
momentMock.subtract.and.returnValue(dateMock);
inject((_$rootScope_, _$controller_, _$q_) => {
$scope = _$rootScope_.$new();
$q = _$q_;
ctrl = _$controller_('contractCancellationCtrl as contractCancellationCtrl', {
moment: momentMock,
});
});
contractCancellationDeferred = $q.defer();
});
it('should expect the controller to be initialized', () => {
expect(ctrl.moment).toEqual(momentMock);
});
});
});
I'm trying to unit test a component method. The question here does not lay out how to access the component method from a unit test.
Specifically, given my Vue component below, how do I access doSomeWork() from my unit test?
Vue component:
<template>
<div id="ThisStuff">
<span>
Some other stuff is going on here
</span>
</div>
</template>
<script>
import foo from 'bar'
export default {
props: {
ObjectWithStuffInIt: [
{
id: 1
bar: false
},
{
id: 2
bar: false
},
]
},
data: {
foo: "foo"
},
methods: {
doSomeWork: function() {
for (var i = 0; i < ObjectWithStuffInIt.length; i++) {
if (foo === "diddly") {
ObjectWithStuffInIt[i].bar = true;
}
}
}
}
}
</script>
My test code:
import {createLocalVue, shallow} from 'vue-test-utils'
import ThisVueFile.test.js from '../../thisPlace/ThatPlace/ThisVueFile.vue'
import Vuex from 'vuex'
const localVue = createLocalVue()
localVue.use(Vuex);
describe('ThisVueFile.test.js', () => {
let user;
let store;
beforeEach(() => {
let getters = {
user: () => user
}
store = new Vuex.Store({ getters })
})
// I need to fill propsData: with some local data here
// because it is server data
// I need to have access to the method
// I need to use local data for `foo` in the test.
it(' When foo is set to -diddly- then set bar to true ', () => {
foo = "diddly";
// run the method in the component here
doSomeWork();
expect(OjbectWithStuffInIt[0].bar.equals(true));
})
})
Calling component method
The wrapper provides access to the component instance via its vm property, so you could call the method directly with:
wrapper.vm.doSomeWork()
Setting props
The mounting options (passed to shallowMount() or mount()) include the propsData property that could be used to initialize the component's props before mounting.
You could also use the wrapper's setProps() after the component has already been mounted.
Example:
it('...', () => {
const wrapper = shallowMount(MyComponent, {
propsData: {
myItems: [
{ id: 200, bar: false },
{ id: 300, bar: false }
]
}
});
// OR
wrapper.setProps({
myItems: [
{ id: 400: bar: true }
]
})
})
Modifying component data property
The mounting options includes the data property that could be used to initialize the component's data before mounting.
You could also use the wrapper's setData() after the component has already mounted.
You could access the component's data property directly through the wrapper's vm property.
Example:
it('...', () => {
const wrapper = shallowMount(MyComponent, {
data() {
return {
foo: 1
}
}
});
// OR
wrapper.setData({ foo: 2 })
// OR
wrapper.vm.foo = 3
})
Full example
Altogether, your test might look similar to this:
import { createLocalVue, shallowMount } from '#vue/test-utils'
import MyComponent from '#/components/MyComponent'
describe('MyComponent', () => {
it('When foo is set to -something-, set bar to true', () => {
const myItems = [
{ id: 200, bar: false },
{ id: 300, bar: false }
]
const localVue = createLocalVue()
const wrapper = shallowMount(MyComponent, {
localVue,
propsData: {
myItems
}
})
wrapper.vm.foo = 'something'
wrapper.vm.doSomeWork()
expect(myItems[0].bar).toBe(true)
})
})
demo
Whe I run my tests with --coverage
yarn run test --coverage
The follow erro appear
component › should render with message if error occour
TypeError: Function.prototype.name sham getter called on non-function
14 | );
15 |
> 16 | expect(wrapper).toMatchSnapshot();
| ^
17 | });
18 |
19 | it("should render if error occour", function() {
at Function.getName (../node_modules/function.prototype.name/implementation.js:31:9)
at displayNameOfNode (../node_modules/enzyme-adapter-utils/build/Utils.js:156:95)
at ReactSixteenAdapter.displayNameOfNode (../node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:605:62)
at typeName (../node_modules/enzyme/build/Debug.js:60:43)
at internalNodeToJson (../node_modules/enzyme-to-json/mount.js:70:31)
at mountToJson (../node_modules/enzyme-to-json/mount.js:93:12)
at Object.<anonymous>.exports.default (../node_modules/enzyme-to-json/index.js:14:32)
at Object.print (../node_modules/enzyme-to-json/createSerializer.js:22:40)
at printPlugin (../node_modules/pretty-format/build/index.js:287:16)
at prettyFormat (../node_modules/pretty-format/build/index.js:485:16)
at Object.throwingMatcher (../node_modules/expect/build/index.js:320:33)
at Object.toMatchSnapshot (src/components/molecules/ErrorBoundary/ErrorBoundary.test.jsx:16:19)
That is my ErrorBoundary component
import React from "react";
export default class extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
this.setState(prevState => ({ ...prevState, hasError: true }));
}
render() {
const { hasError } = this.state;
const { children, message = "Ops, ocorreu um erro. Tente novamente" } = this.props;
return hasError ? <h1>{message}</h1> : children;
}
}
And my test..
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
describe("<ErrorBoundary> component", function() {
it("should render with message if error occour", function() {
function ProblemChild() {
throw new Error("Error thrown from problem child");
}
const wrapper = mount(
<ErrorBoundary message="Ops, algum erro ocorreu">
<ProblemChild />
</ErrorBoundary>
);
expect(wrapper).toMatchSnapshot();
});
});
I've just solved this in my code base. The problem was caused by the missing class name on the export, so your fix is likely to be adding the class name in your ErrorBoundary component and anywhere else it's missing. i.e.
Change: export default class extends React.Component {
To: export default class ErrorBoundary extends React.Component {
Hope it helps!
I'm trying to do a unit test on a Vue component. I'm getting an error when wrapper.find() is used.
Component is as given below:
snackbar.vue
<script>
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters({
visibility: "snackbar/visibility",
type: "snackbar/type",
message: "snackbar/message"
})
},
watch: {
visibility(value) {
if (value) {
$("#snackbar").addClass("show " + this.type);
setTimeout(() => {
$("#snackbar").removeClass("show " + this.type);
this.$store.dispatch("snackbar/close");
}, 3000);
}
}
}
};
</script>
<template>
<div id="snackbar">{{ message }}</div>
</template>
In the testing I want to get a div having snackbar as id using wrapper.find().
It's spec file:
snackbar.spec.js
import SnackBar from '../../../src/modules/Common/_components/snackbar.vue';
import { mount, createLocalVue } from '#vue/test-utils';
import Vue from 'vue'
import Vuex from 'vuex'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('Snackbar component', () => {
let store
beforeEach(() => {
let state = {
isVisible: false,
message: '',
type: ''
}
let getters = {
'snackbar/visibility': (state) => state.isVisible,
'snackbar/type': (state) => state.type,
'snackbar/message': (state) => state.message
}
store = new Vuex.Store({
modules: {
snackbar: {
state,
getters
}
}
})
})
it('renders the correct markup', () => {
let wrapper = mount(SnackBar, { localVue, store })
let snackbar = wrapper.find('#snackbar');
// some test code related to snackbar
})
})
The log is as given below:
cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run
30 05 2018 18:18:57.847:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
30 05 2018 18:18:57.849:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
30 05 2018 18:18:57.855:INFO [launcher]: Starting browser PhantomJS
30 05 2018 18:18:58.293:INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket UwfYAt7yHauyEGfNAAAA with id 26585183
Snackbar component
✗ renders the correct markup
undefined is not a function (evaluating 'vNodes.findIndex(function (node) { return vNode.elm === node.elm; })')
webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:2887:48 <- index.js:145115:83
filter#[native code]
removeDuplicateNodes#webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:2887:0 <- index.js:145115:23
findVNodesBySelector#webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:2917:0 <- index.js:145145:30
findVnodes#webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:2934:0 <- index.js:145162:30
find#webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:2982:0 <- index.js:145210:27
find$$1#webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:3272:0 <- index.js:145500:19
webpack:///test/unit/specs/snackbar.spec.js:38:32 <- index.js:142013:32
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.622 secs / 0.009 secs)
This is a problem with an old version of vue-test-utils. findIndex is not supported in IE, so we have removed findIndex from recent versions.
If you cannot update to the latest #vue/test-utils, you can add a findIndex polyfill before you run the tests—https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex#Polyfill.