Unit testing a React function in component - unit-testing

I need a way to unit test the "edit" function in the code below. It is different form the other questions because my function returns no value.
class QslTable extends React.PureComponent {
this.state = {
data: [{
key: '0',
callSign: {
editable: true,
value: 'F1ABD',
},
QSODate: {
editable: true,
value: '10-05-31',
},
band: {
editable: true,
value: '32',
},
mode: {
editable: true,
value: 'Phone',
},
dxccEntity: {
editable: true,
value: 'France',
},
delete: {
editable: false,
value: 'Delete',
},
}],
};
edit(index) {
const { data } = this.state;
Object.keys(data[index]).forEach((item) => {
if (data[index][item] && typeof data[index][item].editable !== 'undefined') {
data[index][item].editable = true;
}
});
this.setState({ data });
}
}
This doesn't work:
it('should render the component', () => {
const renderedComponent = shallow(<QslTable />);
expect(renderedComponent.find('edit')).toBeDefined();
});
The function doesn't return any value. I have no clue how to test the function. I have looked at the documentation for Jest, but couldn't figure it out. Any help would be appreciated!

Related

chart js not dispalying data array that comes from an axios request

I have an API end point that returns an array of 24 values that I want to use in my chartjs within a vue component.
when the page loads I get no errors but the bars on the charts just don't show and I don't know why.
EDIT: I noticed that the async function returns a promise instead of the actual data:
async filterData() {
await this.$axios.get('/api/data_app/job_count_by_hour/')
.then(response => {
return this.chart_data = response.data;
})
}
here is the data return code, I have a function that populates the chart_data array :
data(){
return {
form:{
day: 'select day',
workspace:'',
machine_family: [],
duration: []
},
res: [],
total:[],
chart_data: [],
url: '/api/jobs/job_count_by_hour/',
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "sunday"],
barChart2: {
labels: ["6h", "7h", "8h", "9h","10h","11h", "12h", "13h", "14h", "15h", "16h", "17h", "18h", "19h", "20h", "21h","22h", "23h", "00h"],
datasets: [{
label: ["popularity"],
backgroundColor:"#f93232" ,
data: this.chart_data
},],
},
}
},
methods: {
async filterData() {
let _url = `${this.url}`
await this.$axios.get(_url)
.then(response => {
this.chart_data = response.data;
})
return this.chart_data
},
},
mounted() {
this.filterData()
}
}
this is the chart component:
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
in the parent component It looks like this:
en <BarChart :labels="barChart2.labels"
:datasets="barChart2.datasets"
:height="100"
>
</BarChart>ter code here
Turns out that when you try to update nested data, the component doesn't re-render.
This is how I solved it, I put the entire object in an update function and call that function when i get my data from the back end, I hope this helps!:
methods: {
onInput(value) {
this.filterData()
},
updateChart(data) {
this.datasets = [{
label: ["popularity"],
backgroundColor:"#f93232",
data: data
}]
},
async loadData() {
await this.$axios.get(this.url)
.then(response => {
this.updateChart(response.data)
})
},
},
mounted() {
this.loadData()
},

apexchart - Get label from database

I'm not sure as to why the labels doesn't work but series works when fetching data from the database. I'm using vue and laravel.
Here is my code
<div id="chart">
<apexchart type="pie" width="380" :options="chartOptions" :series="series"></apexchart>
</div>
export default {
data: () => ({
employees: [],
series: [],
chartOptions: {
chart: {
width: 380,
type: 'pie',
},
labels: [],
responsive: [{
breakpoint: 80,
options: {
chart: {
width: 200
},
legend: {
position: 'bottom'
}
}
}]
}
}),
methods: {
kpiProgress () {
axios.get('/api/employee-kpi-progress', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.series = response.data
})
.catch(error => console.log(error))
},
kpaInfo () {
axios.get('/api/employee-kpa-info', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.chartOptions.labels = response.data
console.log(this.chartOptions.labels)
})
.catch(error => console.log(error))
},
}
}
Made it work. This is a really weird solution since this is my first time directly calling data from a response.
kpaInfo () {
axios.get('/api/employee-kpa-info', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.chartOptions = {
labels: response.data,
}
})
.catch(error => console.log(error))
},

Jest, expected mock function to have been called, but it was not called

Testing lifecycle methods when a VueJS component renders on the transition group.
I've been writing tests for lifecycle methods when the component renders on the transition group of the following VueJS component I've made little progress on getting it to work and would appreciate advice regarding this. I also tried switching between shallow mounting and mounting the component though that seemed to make no difference.
import { shallowMount } from '#vue/test-utils';
import StaggeredTransition from '../src/index';
const staggeredTransitionWrapper = componentData =>
shallowMount(StaggeredTransition, {
...componentData,
});
const staggeredTransition = staggeredTransitionWrapper();
describe('StaggeredTransition.vue', () => {
it('should render a staggered transition component', () => {
expect(staggeredTransition.element.tagName).toBe('SPAN');
expect(staggeredTransition.html()).toMatchSnapshot();
});
it('should mock calling the enter method', () => {
const enterMock = jest.fn();
StaggeredTransition.methods.enter = enterMock;
const staggeredTransitionWrapper2 = componentData =>
shallowMount(StaggeredTransition, { ...componentData });
const staggeredTransition2 = staggeredTransitionWrapper2({
slots: {
default: '<h1 :key="1">Staggered transition test</h1>',
},
});
expect(enterMock).toBeCalled();
});
});
Code for the StaggeredTransition component
<template>
<transition-group
:tag="tag"
:name="'staggered-' + type"
:css="false"
appear
#before-enter="beforeEnter"
#enter="enter"
#leave="leave"
>
<slot />
</transition-group>
</template>
<script>
const { log } = console;
export default {
name: 'StaggeredTransition',
props: {
type: {
type: String,
options: ['fade', 'slide'],
required: false,
default: 'fade',
},
tag: {
type: String,
required: false,
default: 'div',
},
delay: {
type: Number,
required: false,
default: 100,
},
},
methods: {
beforeEnter(el) {
console.log('beforeEnter');
el.classList.add(`staggered-${this.type}-item`);
},
enter(el, done) {
console.log('enter');
setTimeout(() => {
el.classList.add(`staggered-${this.type}-item--visible`);
done();
}, this.getCalculatedDelay(el));
},
leave(el, done) {
console.log('leave');
setTimeout(() => {
el.classList.remove(`staggered-${this.type}-item--visible`);
done();
}, this.getCalculatedDelay(el));
},
getCalculatedDelay(el) {
console.log('getCalculatedDelay');
if (typeof el.dataset.index === 'undefined') {
log(
'data-index attribute is not set. Please set it in order to
make the staggered transition working.',
);
}
return el.dataset.index * this.delay;
},
},
};
</script>

apollo-link-state cache.writedata results in Missing field warning

When I call a mutation on my client I get the following warning:
writeToStore.js:111 Missing field updateLocale in {}
This is my stateLink:
const stateLink = withClientState({
cache,
resolvers: {
Mutation: {
updateLocale: (root, { locale }, context) => {
context.cache.writeData({
data: {
language: {
__typename: 'Language',
locale,
},
},
});
},
},
},
defaults: {
language: {
__typename: 'Language',
locale: 'nl',
},
},
});
And this is my component:
export default graphql(gql`
mutation updateLocale($locale: String) {
updateLocale(locale: $locale) #client
}
`, {
props: ({ mutate }) => ({
updateLocale: locale => mutate({
variables: { locale },
}),
}),
})(LanguagePicker);
What am I missing?
I was getting the same warning and solved it by returning the data from the mutation method.
updateLocale: (root, { locale }, context) => {
const data = {
language: {
__typename: 'Language',
locale,
}
};
context.cache.writeData({ data });
return data;
};
At the moment, apollo-link-state requires you to return any result. It can be null too. This might be changed in the future.

AngularJS, Jasmine, Chutzpah... Unit testing a filter?

I am just trying to get a better understanding of Jasmine unit tests with AngularJS. So I setup a test around an existing experimental project I started. I'll just start off with the code, my question is at the bottom.
First my app declaration:
(function () {
"use strict";
angular.module('iconic', [])
.constant('config', {
debug: true,
version: '1.0.0.1'
})
.value('globalStatus', {
currentArea: null,
progress: null,
notice: [
{ title: 'Notice 1 Title', message: 'Notice 1 Message' },
{ title: 'Notice 2 Title', message: 'Notice 1 Message' }
]
});
}());
Then a factory to get data (static now but would be an AJAX call):
(function () {
"use strict";
angular.module('iconic')
.factory('data', ['$http', function ($http) {
function areas() {
return [
{ name: 'home', text: 'Home', enabled: true, active: false },
{ name: 'gallery', text: 'Gallery', enabled: true, active: false },
{ name: 'services', text: 'Services', enabled: true, active: false },
{ name: 'pricing', text: 'Pricing', enabled: true, active: false },
{ name: 'test', text: 'Test', enabled: false, active: false }
];
}
return {
getAreas: areas
};
}]);
}());
Then my controller with the filter:
(function () {
"use strict";
angular.module('iconic')
.controller('NavController', ['$scope', 'data', function ($scope, data) {
$scope.menus = data.getAreas();
}])
.filter('EnabledFilter', ['config', function (config) {
return function (menus) {
if (config.debug)
console.log('matchEnabled', arguments);
var filtered = [];
angular.forEach(menus, function (menu) {
if (menu.enabled) {
filtered.push(menu);
}
});
return filtered;
};
}]);
}());
And then my actual Jasmine test (running this with Chutzpah):
(function () {
"use strict";
var staticData = [
{ name: 'home', text: 'Home', enabled: true, active: false },
{ name: 'gallery', text: 'Gallery', enabled: true, active: false },
{ name: 'services', text: 'Services', enabled: true, active: false },
{ name: 'pricing', text: 'Pricing', enabled: true, active: false },
{ name: 'test', text: 'Test', enabled: false, active: false }
];
describe("NavController Tests", function () {
//Mocks
//Mocks
var windowMock, httpBackend, _data;
//Controller
var ctrl;
//Scope
var ctrlScope;
//Data
var storedItems;
beforeEach(function () {
module('iconic');
});
beforeEach(inject(function ($rootScope, $httpBackend, $controller, data) {
//Mock for $window service
windowMock = { location: { href: "" } };
//Creating a new scope
ctrlScope = $rootScope.$new();
//Assigning $httpBackend mocked service to httpBackend object
httpBackend = $httpBackend;
_data = data;
storedItems = staticData;
//Creating spies for functions of data service
spyOn(data, 'getAreas').andCallThrough();
$controller('NavController', { $scope: ctrlScope, data: _data});
}));
it("should call getAreas on creation of controller", function () {
expect(_data.getAreas).toHaveBeenCalled();
});
});
}());
So this first and simple test to make sure getAreas gets called passes just fine. But I would like to add a test to basically make sure that the filter result is filtering out data from the factory where enabled is false. Any idea how I would go about doing that with Jasmine?