Vue3/Jest - Line break problem during a test - jestjs

I tried to simulate a mouseover in my test, but i have a problem when i use .contain in an expect. The test doesn't pass because of the page render.
Here the result of the test:
Expected substring: "<div id=\"title\"><!--v-if--></div>"
Received string: "<div id=\"title\">
<!--v-if-->
</div>"
Here my code:
describe('mouse event', function() {
test('over change', async (done) => {
const Component = defineComponent({
template: '<div id="title" #mouseover="hoveredIcon"><span v-if="hovered">Hello World</span></div>',
data() {
return {
hovered: false,
}
},
methods: {
hoveredIcon() {
this.hovered = true
},
}
})
const wrapper = mount(Component)
expect(wrapper.html()).toContain('"<div id=\"title\"><!--v-if--></div>"')
wrapper.find("#title").trigger("mouseover");
wrapper.vm.$nextTick( () => {
expect(wrapper.html()).toContain('<div id=\"title\"><span>Hello World!</span></div>')
done();
});
})
})
How can i get the received string on a single line? Or how to made the expect part in few line to match perfectly?
expect(wrapper.html()).toContain('<div id="title"><!--v-if--></div>')
to
expect(wrapper.html()).toContain('<div id="title">
<!--v-if-->
</div>')
Any better solutions?
Thanks for your help

One solution found was to use directly \n directly in the value expected.
expect(wrapper.html()).toContain('\n \n')

Related

Can't get html element using js file in SPFX

I am trying to build dynamic content from a SharePoint list using SPFX. I'd like to use jQuery to build an accordion view of the data. The issue is that I can't even seem to get the element once the page is rendered.
In my code I am requiring a file called ota.js with the following code:
console.log('Start');
function otaExpand(){
console.log('otaExpand Function Called');
let spListContainer = document.getElementById('spListContainer');
console.log(spListContainer);
}
window.addEventListener("load", otaExpand());
In my ts file this is my render method:
public render(): void {
this.domElement.innerHTML = `
<div>
<div id="spListContainer">TEST</div>
</div>
`;
//this._renderListAsync();
//($('.accordion', this.domElement) as any).accordion();
}
When I review the console, I get my messages, but the element itself comes back as null.
console.log
I am using SharePoint 2019 on premise with the following configuration.
+-- #microsoft/generator-sharepoint#1.10.0
+-- gulp-cli#2.3.0
`-- yo#2.0.6
node --version
v8.17.0
I should also mention I am using TypeScript with no JavaScript framework.
Does anyone know why I can't access this element from my js file?
Thanks!
My overall goal is to call list data and apply an accordion style to it (https://jqueryui.com/accordion), but I can't even get passed capturing the element to change it.
I've tried calling my code from a js file as well as trying to put the code directly in the html. Neither worked.
OK, I finally figured out what I was doing wrong. I was calling my jQuery in the render() method rather than in _renderList where this.domElement actually makes sense.
Here's my code in case anyone wants to avoid the pain I put myself through. This allows you to specify a list in the site and you just need to add the fields you want to display.
import { Version } from '#microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneChoiceGroupOption,
IPropertyPaneConfiguration,
PropertyPaneChoiceGroup,
PropertyPaneCustomField,
PropertyPaneTextField
} from '#microsoft/sp-webpart-base';
import { escape } from '#microsoft/sp-lodash-subset';
import styles from './GetSpListItemsWebPart.module.scss';
import * as strings from 'GetSpListItemsWebPartStrings';
import {
SPHttpClient,
SPHttpClientResponse
} from '#microsoft/sp-http';
import * as jQuery from 'jquery';
import 'jqueryui';
import { SPComponentLoader } from '#microsoft/sp-loader';
import PropertyPane from '#microsoft/sp-webpart-base/lib/propertyPane/propertyPane/PropertyPane';
export interface IGetSpListItemsWebPartProps {
title: string;
description: string;
listField: string;
}
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
ID: string;
Title: string;
Website: {
Description : string,
Url : string
};
Description : string;
}
export default class GetSpListItemsWebPart extends BaseClientSideWebPart<IGetSpListItemsWebPartProps> {
private _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/web/lists/GetByTitle('" + this.properties.listField + "')/Items",SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
private _renderListAsync(): void {
this._getListData()
.then((response) => {
this._renderList(response.value);
})
.catch(() => {});
}
private _renderList(items: ISPList[]): void {
let listData = `
<h1>${this.properties.title}</h1>
<h2>${this.properties.description}</h2>
<div class="accordion">
`;
items.forEach((item: ISPList) => {
let Description : string;
item.Description ? Description = item.Description : Description = "";
listData += `
<h3> ${item.Title}</h3>
<div>
<table>
<tr>
<td>OTA URL</td>
<td>${item.Website.Description}</td>
</tr>
<tr>
<td>Description</td>
<td>${Description}</td>
</tr>
</table>
</div>
`;
});
listData += '</div>';
this.domElement.innerHTML = listData;
const accordionOptions: JQueryUI.AccordionOptions = {
animate: true,
collapsible: true,
icons: {
header: 'ui-icon-circle-arrow-e',
activeHeader: 'ui-icon-circle-arrow-s'
}
};
jQuery('.accordion', this.domElement).accordion(accordionOptions);
}
public render(): void {
this._renderListAsync();
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('title',{
label: strings.TitleFieldLabel
}),
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyPaneTextField('listField', {
label: strings.ListFieldLabel
})
]
}
]
}
]
};
}
public constructor() {
super();
SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}
}
Your code from the "ota.js" file is probably called before your HTML is initialized (i.e. before the "render()" function is executed). To make sure this is the case, you could add log to the "render()" function to see when it's called.
In other words, "window.load" event happens long before "render()" function is called. This is how web parts are loaded - dynamically after full load of the page. Or "window.load" does not happen at all - web parts may be loaded by the user when using the page designer, i.e. without page reload.
To fix the issue, you should get the element after it's created, i.e. after the "render()" function creates the element you are trying to get.

noUISlider - How to destroy the noUiSlider without deleting the element?

I have an element in my HTML and it has some HTML inside it. I am converting that to noUISlider at the click of a button (Start Slider). There is another button to hide the slider (Hide Slider). I want to hide the slider but keep the and also the HTML inside it. I am trying the slider.nouislider.destroy(); but it deletes the element completely.
Any help on this is appreciated.
Thank you.
Suhas
Okay, this is what I did and it worked for me. Hopefully, it could be helpful to someone or if there is a better way to do this, please let me know.
My HTML is
<div class="sliderContainer" id="slider">some HTML code</div>
And My JS code is
var sliderActive = false;
function createSlider() {
if (!sliderActive) {
sliderActive = true;
noUiSlider.create(slider, {
start: [360, 1080],
connect: true,
step: 15,
behaviour: 'drag',
tooltips: [
{
to: function (value) {
return processValue(value);
},
from: function (value) {
return processValue(value);
}
},
{
to: function (value) {
return processValue(value);
},
from: function (value) {
return processValue(value);
}
},
],
range: {
'min': 0,
'max': 1440,
}
});
}
}
function destroySlider() {
sliderActive = false;
$('.sliderContainer').attr('class', 'sliderContainer');
$('.noUi-base').remove();
delete slider.noUiSlider;
slider = document.getElementById('slider');
}
Thank you.

Add hash of most recent git commit to footer of pdf via markdown-pdf

I am using markdown-pdf via gulp to convert .md files to .pdf. I want to get the sha of the latest git commit and add it to the footer. I can get the hash like so in my gulpfile.js (found the answer):
revision = require('child_process')
.execSync('git rev-parse HEAD')
.toString().trim();
But how can I get that into my footer?
Below is my code for markdown-pdf that I am using in my gulpfile.js:
function docsToPdf() {
return src(["Views/Documentation/Files/*.md", "!Views/Documentation/Files/_README.md"])
.pipe(markdownPdf({
preProcessMd: preProcessMd,
remarkable: {
html: true
},
paperBorder: "1cm",
runningsPath: "Content/Pdf/assets/js/runnings.js",
cssPath: "Content/Pdf/assets/css/pdf.min.css"
}))
.pipe(dest("Content/Pdf"))
}
And my runnings.js file:
module.exports = {
header: {
height: '2cm',
contents: function (pageNum) {
if (pageNum == 1) {
return '<header class="pdf-header" style="padding-bottom: 20px;"><h2 style="text-align:center;margin:0;">Documentation</h2></header>'
}
return ''
}
},
footer: {
height: '1.5cm',
contents: function (pageNum, numPages) {
return '<footer class="pdf-footer" style="padding-top:20px;"><p style="float:left;width:33.33%;margin:0;font-size:10px;">' + new Date().toDateString() + '</p><p style="float:left;width:33.33%;margin:0;font-size:10px;text-align:center;">© 2020</p><p style="float:right;width:33.33%;margin:0;font-size:10px;text-align:right;">Page ' + pageNum + ' of ' + numPages + '</p></footer>'
}
}
}
And my preProccessMd:
function preProcessMd() {
var splitter = split()
var docsUrl = "https://example.org/docs/";
var urlOne = /\[\[((?:(?!\[\[).)*?)\|(.*?)]]/g;
var urlImg = /(\()(images)/g;
var replacer = through(function (data, path) {
this.queue(
data
.replace(urlOne, (_, x, y) => `[${x}](${docsUrl}${y.replace(/(?!^)[A-Z]/g, '-$&').toLowerCase()})`)
.replace(urlImg, "$1$2".replace("$2", "content/images/docs"))
+ "\n"
)
})
splitter.pipe(replacer)
return duplexer(splitter, replacer)
}
The best way to do this would be to use the preProcessMd method to inject the SHA into the footer. You do seem to have the preprocessor defined in preProcessMd: preProcessMd,. Is that actually doing anything? If so, what is the definition?
EDIT, after update from OP: Quick and dirty solution would be to use an empty span where you want the SHA to go. Then look for that span and replace with the SHA in your preProcessMd. For e.g., <span class="git-hash"></span>. Then replace <span class="git-hash"> with <span>YOUR-SHA.
You might need to update your gulp task like so:
function docsToPdf() {
revision = require('child_process')
.execSync('git rev-parse HEAD')
.toString().trim();
return src(["Views/Documentation/Files/*.md", "!Views/Documentation/Files/_README.md"])
.pipe(markdownPdf({
preProcessMd: preProcessMd.bind(this, revision),
remarkable: {
html: true
},
paperBorder: "1cm",
runningsPath: "Content/Pdf/assets/js/runnings.js",
cssPath: "Content/Pdf/assets/css/pdf.min.css"
}))
.pipe(dest("Content/Pdf"))
}
And your function preProcessMd() { to function preProcessMd(revision) {
NOTE: I'm unsure if the preProcessMd.bind(this, ... is going to be problematic or not.

Jest / Enzyme html function is not multiline and indented

I'm snapshot testing the HTML from a React component:
describe('something', () => {
const wrapper = mount(
<MockProvider>
<MyCompoent />
</MockProvider>,
);
test('matches the snapshot', () => {
expect(wrapper.html()).toMatchSnapshot();
});
});
This works however the snapshot is minified:
exports[`MyCompoent something`] = `"<section class=\\"wrapper\\"><a class=\\"backLink\\" href=\\"#gift-type\\"><i class=\\"icon ArrowLeft backLinkIcon\\"><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 64 64\\"><path fill=\\"currentColor\\" fill-rule=\\"nonzero\\" d=\\"M19.053 30.01h32.12v3h-32.38l13.28 13.28-2.121 2.121L13 31.458 30.004 16l2.018 2.22z\\"></path></svg></i>Back</a><div cla....
How can I have the HTML nicely multiline and indented? The same thing happens when I console.log(wrapper.html())
In my jest-config.js I already have this:
module.exports = {
snapshotSerializers: ['enzyme-to-json/serializer'],
};
If I don't use the render method (eg expect(wrapper).toMatchSnapshot();) then the multiline and indentation works fine.

can't test ember component that appends a div to the dom

I have a ember-cli-addon that adds a component which appends a div with a specific class to the consuming application. I'm trying to test this integration and having difficulty to setup the test.
I have tried to unit test the component as well but that doesn't work quite as expected. Here's what I've tried:
I've copied the component from my addon directory to tests/dummy/components/jquery-backstretch.js to make it available to the dummy test application:
jquery-backstretch.js
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'jquery-backstretch',
image: null,
selector: 'body',
fade: 0,
duration: 5000,
centeredX: true,
centeredY: true,
setupJquerybackstretch: function() {
var image = this.get('image');
if (! Ember.isEmpty(image)) {
var options = {
fade: this.get('fade'),
centeredX: this.get('centeredX'),
centeredY: this.get('centeredY')
};
var jqbsImage;
if (Ember.typeOf(image) === 'string') {
jqbsImage = 'assets/' + image;
} else if (Ember.isArray(image)) {
options.duration = this.get('duration');
jqbsImage = image.map(function(img) {return 'assets/' + img;});
} else {
Ember.Logger.error('Ember JQuery-Backstretch: Unsupported "image" format.');
}
Ember.$(this.get('selector')).backstretch(jqbsImage, options);
} else {
Ember.Logger.error('Ember JQuery-Backstretch: image not supplied.');
}
}.on('didInsertElement'),
teardownJquerybackstretch: function() {
Ember.$(this.get('selector')).backstretch('destroy');
}.on('willDestroyElement')
});
this causes the component to append the img to the body of the test page and not to #ember-testing-container, changing the selector to #ember-testingn-container puts the img in the right place but the test can't find it:
tests/acceptance/jquery-backstretch.js
import Ember from 'ember';
import {
module,
test
} from 'qunit';
import startApp from '../../tests/helpers/start-app';
var application;
module('Acceptance: JqueryBackstretch', {
beforeEach: function() {
application = startApp();
},
afterEach: function() {
// Ember.run(application, 'destroy');
}
});
test('backstretch added to body tag', function(assert) {
visit('/');
andThen(function() {
assert.equal(find('.backstretch > img').length, 1, 'Backstretch found');
});
});
application.hbs
<h2 id="title">Welcome to Ember.js</h2>
{{jquery-backstretch image="img/emberjs.png"}}
{{outlet}}
the test is not passing, it can't find the image, I also tried to test the component and append it to the DOM then test to see if it's in the DOM but that didn't yield better results.
How can I test this please?

Resources