Unit test a V-If with Jest - html

How do I test the following v-if on my parent component using Jest?
Parent:
<div class="systemIsUp" v-if="systemStatus == true">
foo
</div>
<div class="systemIsDown" v-else>
bar
</div>
<script>
export default {
name: 'File Name',
data () {
return {
systemStatus: null,
}
},
</script>
Here is my current setup for testing if those divs render when I change the value of the systemStatus variable
Unit Test:
import { shallowMount } from '#vue/test-utils'
import FileName from 'path'
describe('FileName', () => {
//Declare wrapper for this scope
const wrapper = shallowMount(FileName)
it('Should display message saying that the system is down if "systemStatus" data variable is false', () => {
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false})
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
});
});
I have tried using contains and toContain instead of includes but still cannot get it to work, Jest returns the following:
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false })
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
^
Clearly it cannot see the systemIsDown div at all and does not think it exists hence why the first expect passes but how can I get it to see the div when the systemStatus variable is updated?
Thanks

Changed around the assertion to look for specific CSS selector as follows:
wrapper.setData({ systemStatus: false})
expect(wrapper.find(".systemIsDown")).toBeTruthy()

This should work, if you want to check given DOM element has been created (or not):
expect(wrapper.find(".systemIsDown").exists()).toBe(true) // or false
more here

Related

Implement conditional Routing in Angular

I am trying to implement the following functionality. When a button is clicked to check a condition, condition should be a variable (or a sum in my case) different from undefined (if different then success). Then either go to the success-page if the condition is met or to display the fail page if the condition is not met (+ if nothing was changed in the page just go to the success-page).
.html
<div class="d-flex justify-content-center">
<button type="button" (click)="updatePost()" routerLink="/success-page">Save</button>
The updatePost() method in the .ts file simply calls a function from the service and updates a user if some properties are changed (I have some input textboxes in the .html file).
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(response => {
}, error => {
console.log(error);
})
}
I tried many ways but the functionality is not correct. The problem might be the order in which I tried to call the function and implement the logic.
Both pages are registered as routes.
const routes: Routes = [
{path: 'success-page', component: DisplaySuccessComponent},
{path: 'fail-page', component: DisplayFailPageComponent},
];
For that you should use Router from constructor. For that you need to provide constructor(private router: Router) {} then you need to check variable should not be undefined, null or not expected condition, then you need to route like
this.router.navigate(['fail-page']); and if not undefined, not null and as expected condition then you can navigate by using this.router.navigate(['success-page']);. So, your final code like below:-
// In HTML:-
<button type="button" (click)="updatePost()">Save</button>
// In ts:-
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(response => {
this.router.navigate(['success-page']);
}, error => {
this.router.navigate(['fail-page']);
console.log(error);
})
}
you should not use routerLink in this case but navigate inside the upadtePost()function i.e:
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(
response => {
this.router.navigate('/success-page');
},
error => {
console.log(error);
this.router.navigate('/fail-page');
});
}

Rest-spread not being transpiled when targeting edge with NextJS

I am trying to transpile my ES6 code via Babel, I am using the next/babel preset along with preset-env and I'm using the browsers: defaults target.
The NextJS preset comes with #babel/plugin-proposal-object-rest-spread in its plugins array, I'm wondering why I am getting an error when testing on edge that says Expected identifier, string or number, and when looking in the compiled JS for the error, I see it happens when {...t} occurs.
Here is my babel.config.js:
module.exports = {
presets: [
[
'next/babel',
{
'#babel/preset-env': {
targets: {
browsers: 'defaults'
},
useBuiltIns: 'usage'
}
}
]
],
plugins: [
'#babel/plugin-proposal-optional-chaining',
'#babel/plugin-proposal-nullish-coalescing-operator',
['styled-components', { ssr: true, displayName: true, preprocess: false }],
[
'module-resolver',
{
root: ['.', './src']
}
]
],
env: {
development: {
compact: false
}
}
};
Any help on this would be greatly appreciated!
In the end my problem was related to a package that was not being transpiled by babel. My solution was to use NextJS' next-transpile-modules plugin to get babel to transpile the package code into something that would work on the browsers I need.
Here's an example of my NextJS webpack config with the package I need transpiled specified:
const withTM = require('next-transpile-modules');
module.exports = withTM({
transpileModules: ['swipe-listener']
});
SCRIPT1028: Expected identifier, string or number error can occur in 2 situations.
(1) This error get trigger if you are using trailing comma after your last property in a JavaScript object.
Example:
var message = {
title: 'Login Unsuccessful',
};
(2) This error get trigger if you are using a JavaScript reserved word as a property name.
Example:
var message = {
class: 'error'
};
solution is to pass the class property value as a string. You will need to use bracket notation, however, to call the property in your script.
Reference:
ERROR : SCRIPT1028: Expected identifier, string or number

Webpack override behavior of require

I have a module I'm importing during my webpack that does something like so:
'use strict';
module.exports = {
position: true,
gfm: true,
commonmark: false,
footnotes: false,
pedantic: false,
blocks: require('./block-elements.json')
};
Webpack rewrites this module like so:
module.exports = {
position: true,
gfm: true,
commonmark: false,
footnotes: false,
pedantic: false,
blocks: __webpack_require__(/*! ./block-elements.json */ "./block-elements.json")
};
Another function is then assuming that the blocks member is a string.
Is there a way to override the writing of the webpack_require and replace it with my own function that loads the json in a string?
Finally fixed by writing my own loader and setting the default property on the module exports explicitly.
// Code for the loader
module.exports = function(source) {
// Just inline the source and fix up defaults so that they don't
// mess up the logic in the setOptions.js file
return `module.exports = ${source}\nmodule.exports.default = false`;
}
The other script was enumerating the keys of the returned object and the 'default' key was messing it up. However if a key had a type of Boolean it would let it through.
Specifically it was a problem with the remark-parser lib used for hosting markdown in a react control.

getMultiCapabilities not working with arrow function

getMultiCapabilities seems not working with arrow function. So I defined 'getMultiCapabilities' function rather than 'multiCapabilities' property in the protractor config.ts like this:
export let config: Config = {
...
getMultiCapabilities: () => { // this doesn't work;
... // replacing it with "function() {" is okay
},
beforeLaunch: () => { // this works fine
...
},
...
}
This results in "Error: Debug Failure. False expression: position cannot precede the beginning of the file". Replacing arrow with 'function' works fine. Is this a protractor bug? or did I miss something?

How to make use of :id returned by stateParams of stateProvider in angularJS

Am looking to read & display this JSON array of objects.
[
{
"pictitle":"title1 ",
"thumbpicurl":"url1",
"bigpicurl":"url2",
"picdescription":"text text"
},
{
"pictitle":"title2 ",
"thumbpicurl":"url1",
"bigpicurl":"url2",
"picdescription":"text text"
},
]
JSON is served by this factory.
angular.module('picService', ['ngResource'])
.factory('picsFactory',function($resource){
return $resource('pictures.json',{},{
'getData': {method:'GET', isArray:true}
}
);
});
This Markup displays mini thumbnails using the thubmpicURL of the JSON data.
<div class="miniImages">
<a href="/home/{{$index}}">
<img src="{{pic.thumbpicurl}}" class='thumbnail'/> </a>
</div>
Am using stateProvider for routing to display enlarged version of the picture when user selects a thumbnail.
$stateProvider.state( 'home/:id', {
url: '/home/:id',
views: {
"main": {
controller: 'picCtrl',
templateUrl: 'home/pics-detail.tpl.html'
}
}
});
First controller returns the JSON picture data.
.controller('HomeCtrl', function HomeController( $scope,picsFactory ) {
picsFactory.getData(function(picturedata){
$scope.picParams = picturedata;
});
})
Second controller is looking to set properties of each picture object. Am not sure what is the correct syntax to set the stateParams to the picture object.
.controller('picCtrl', function picController( $scope, $stateParams ) {
$scope.picture = $scope.picParams[$stateParams.id];
})
;
I get this error in the debuge console. I think it doesn't like my $scope.picParams[$stateParams.id] in picCtrl controller.
Is this the correct way to make use of $stateParams
TypeError: Cannot read property '0' of undefined
--
ANSWER:
I modified picCtrl to inject picsFactory and with this change it looks to work now.
.controller('picCtrl', function picController( $scope, $stateParams, picsFactory ) {
picsFactory.getData(function(picturedata){
$scope.picture = picturedata[$stateParams.id];
});
})
;
The reason for this could be that the async call of getData on HomeCtrl may not be complete before your second controller picCtrl is initialized and hence picParams is null.
Also HomeCtrl should be parent state or declared on parent html of ui-view for the picCtrl to be able to access what has been set by HomeCtrl