Cannot read properties of undefined (reading 'transition') - Swiper & VueJS & Ionic - vue.js

I can't use the Swiper slideNext function in VueJS with Ionic.
I tried the demo codes from the official Swiper website, without success...
Here is my code:
<template>
<ion-page>
...
<ion-row class="mainRow">
<ion-col size="12">
<ion-row>
<div class="swiper">
<div
class="swiper-slide"
v-for="(question, index) in qst"
:key="`question_${index}`"
>
...
</ion-page>
</template>
<script>
setup() {
const swiperRef = ref(null);
const [slideSpace, setSlideSpace] = useState(0);
const swiper = new Swiper(".swiper", {
speed: 400,
slidesPerView: 1,
spaceBetween: slideSpace,
controller: {
control: swiperRef,
},
on: {
slideChange: function (e) {
setCurrentQuestion(e.activeIndex + 1);
},
},
});
const handleAnswerClick = (event, answer, question) => {
...
setTimeout(() => {
isCorrect && setScore((score) => score + 1);
event.target.setAttribute("color", "light");
swiper.slideNext(); // this line is problematic
checkIfComplete();
}, 1000);
};
The error :
it comes from the Swiper module

Related

vue chartjs not rendering when have a change in chartOption

I'm building a chart in vuejs using composition API, chartjs#4.2, and vue-chartjs#5.2.0
however, I'm not managing to keep the options and data reactive, so I built a button that when active the zoom would be active, and when inactive it would be reset. But I'm not managing to keep this reactivity within the component<Bar>. In future I would make the grafico bars work as a filter in other visuals (just like Power BI). Could someone help me?
I have a js file that contains the opcoes and the dataset :
export const optionBar = {
responsive: true,
maintainAspectRatio: true,
plugins: {
datalabels: {
formatter: function(values) {
return new Intl.NumberFormat('pt-br',{ maximumFractionDigits: 2, minimumFractionDigits:2, }).format(values)
}
},
zoom: {
zoom: {
wheel: {
enabled: true,
},
drag: {
enabled: true,
backgroundColor: 'rgba(12, 173, 241, 0.10)'
},
pinch: {
enabled: true
},
mode: 'x'
}
}
}
}
export const dataSet = {
labels: [1,2,3,4],
datasets: [
{
label: `test`,
data: null,
},
],
}
I can see the chartOption change in the console log and template with {{ }} but my chart does not update accordingly. From what I saw in the document, according to the updated vers/ion (2022-23) the prop :options would be 'commending' any changes in options by containing the watch in vue-chartjs:
<template>
//Toggle Button that change the boolean value and active changes in chartOption
<button #click="ZoomAtivo" > {{zoomEnable}} </button> {{chartOptions.plugins }}
<div class="card ">
<div class="card-body">
<div class="card-header border-0 d-flex justify-content-between">
<h4 class="card-title mb-0">
Serie Temporal
</h4>
<div class="d-flex p-2">
<div
v-for="value in dateF" :key="value.id"
class="btn-group btn p-0 mx-1" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" name="btnradio" :id="value.id_date_mode" :checked="value.check" />
<label class="btn btn-primary mb-0" :for="value.id_date_mode">
{{value.date_mode}}</label>
</div>
<p v-if="dateF == 1"> teste</p>
</div>
</div>
<Bar v-if="load" class="STChart" :data="datasets" :options="chartOptions"
:updateMode="'none'" />
</div>
</div>
</template>
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
import zoomPlugin from 'chartjs-plugin-zoom';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import moment from 'moment'
import { ref, reactive} from 'vue'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, zoomPlugin, ChartDataLabels)
import {optionBar,dataSet} from './options.js'
import { dateFilter } from '#/components/date-mode';
export default {
components: { Bar } ,
setup() {
console.log(Bar)
const chart = ref()
const zoomEnable = ref(false)
const data = ref([])
const dateF = reactive(dateFilter)
const chartOptions =reactive(optionBar)
const load = ref(false)
const data_mov = ref()
const sobra_perda = ref()
const datasets = reactive(dataSet)
const label = ref()
datasets.labels = data_mov
datasets.datasets[0].data = sobra_perda
datasets.datasets[0].label = `Sobra_Perda`
const zmm = reactive({
zoom: {
wheel: {
enabled: true,
},
drag: {
enabled: true,
backgroundColor: 'rgba(12, 173, 241, 0.10)'
},
pinch: {
enabled: true
},
mode: 'x'
}
})
const ZoomAtivo = () => {
zoomEnable.value = !zoomEnable.value
if(zoomEnable.value) {
chartOptions.plugins.zoom = zmm
console.log(chartOptions.plugins.zoom)
} else {
chartOptions.plugins.zoom=null
console.log(chartOptions.plugins.zoom)
}
}
async function DateChart(starDate, endDate, p_items) {
starDate = `01-01-2020`
endDate = `31-12-2022`
const url = `http://localhost:1800/dash/Date/${starDate}/${endDate}`
const respons = await fetch(url, {
method: 'POST',
body: JSON.stringify({
empresa: JSON.parse(localStorage.getItem('companiesGlobalFilter')),
items: p_items
}),
headers: {
'Content-type': 'application/json; charset=UTF-8'
},
});
data.value = await respons.json()
const title = Object.keys(data.value[0])
const _Sobra =data.value.map(v => v.sobra_perda)
const _date_movimento =data.value.map(x => {
let datee = new Date(x.date_movimento)
const data = moment(datee).utc()
datee = data.format('MM/YYYY')
return datee
})
data_mov.value = _date_movimento
sobra_perda.value = _Sobra
load.value = true
label.value = title
return data_mov
}
return {
chartOptions,
datasets,
load, data_mov,
sobra_perda,dateF,
zoomEnable, chart, ZoomAtivo
}
}
}
</script>
<style scoped>
#import './css/chartjs.css';
</style>

Nuxt.js Hackernews API update posts without loading page every minute

I have a nuxt.js project: https://github.com/AzizxonZufarov/newsnuxt2
I need to update posts from API every minute without loading the page:
https://github.com/AzizxonZufarov/newsnuxt2/blob/main/pages/index.vue
How can I do that?
Please help to end the code, I have already written some code for this functionality.
Also I have this button for Force updating. It doesn't work too. It adds posts to previous posts. It is not what I want I need to force update posts when I click it.
This is what I have so far
<template>
<div>
<button class="btn" #click="refresh">Force update</button>
<div class="grid grid-cols-4 gap-5">
<div v-for="s in stories" :key="s">
<StoryCard :story="s" />
</div>
</div>
</div>
</template>
<script>
definePageMeta({
layout: 'stories',
})
export default {
data() {
return {
err: '',
stories: [],
}
},
mounted() {
this.reNew()
},
created() {
/* setInterval(() => {
alert()
stories = []
this.reNew()
}, 60000) */
},
methods: {
refresh() {
stories = []
this.reNew()
},
async reNew() {
await $fetch(
'https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty'
).then((response) => {
const results = response.slice(0, 10)
results.forEach((id) => {
$fetch(
'https://hacker-news.firebaseio.com/v0/item/' +
id +
'.json?print=pretty'
)
.then((response) => {
this.stories.push(response)
})
.catch((err) => {
this.err = err
})
})
})
},
},
}
</script>
<style scoped>
.router-link-exact-active {
color: #12b488;
}
</style>
This is how you efficiently use Nuxt3 with the useLazyAsyncData hook and a setInterval of 60s to fetch the data periodically. On top of using async/await rather than .then.
The refreshData function is also a manual refresh of the data if you need to fetch it again.
We're using useIntervalFn, so please do not forget to install #vueuse/core.
<template>
<div>
<button class="btn" #click="refreshData">Fetch the data manually</button>
<p v-if="error">An error happened: {{ error }}</p>
<div v-else-if="stories" class="grid grid-cols-4 gap-5">
<div v-for="s in stories" :key="s.id">
<p>{{ s.id }}: {{ s.title }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { useIntervalFn } from '#vueuse/core' // VueUse helper, install it
const stories = ref(null)
const { pending, data: fetchedStories, error, refresh } = useLazyAsyncData('topstories', () => $fetch('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty'))
useIntervalFn(() => {
console.log('refreshing the data again')
refresh() // will call the 'topstories' endpoint, just above
}, 60000) // every 60 000 milliseconds
const responseSubset = computed(() => {
return fetchedStories.value?.slice(0, 10) // optional chaining important here
})
watch(responseSubset, async (newV) => {
if (newV.length) { // not mandatory but in case responseSubset goes null again
stories.value = await Promise.all(responseSubset.value.map(async (id) => await $fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)))
}
})
function refreshData() { refreshNuxtData('topstories') }
</script>

Vue 3 how to get information about $children

This my old code with VUE 2 in Tabs component:
created() {
this.tabs = this.$children;
}
Tabs:
<Tabs>
<Tab title="tab title">
....
</Tab>
<Tab title="tab title">
....
</Tab>
</Tabs>
VUE 3:
How can I get some information about childrens in Tabs component, using composition API? Get length, iterate over them, and create tabs header, ...etc? Any ideas? (using composition API)
This is my Vue 3 component now. I used provide to get information in child Tab component.
<template>
<div class="tabs">
<div class="tabs-header">
<div
v-for="(tab, index) in tabs"
:key="index"
#click="selectTab(index)"
:class="{'tab-selected': index === selectedIndex}"
class="tab"
>
{{ tab.props.title }}
</div>
</div>
<slot></slot>
</div>
</template>
<script lang="ts">
import {defineComponent, reactive, provide, onMounted, onBeforeMount, toRefs, VNode} from "vue";
interface TabProps {
title: string;
}
export default defineComponent({
name: "Tabs",
setup(_, {slots}) {
const state = reactive({
selectedIndex: 0,
tabs: [] as VNode<TabProps>[],
count: 0
});
provide("TabsProvider", state);
const selectTab = (i: number) => {
state.selectedIndex = i;
};
onBeforeMount(() => {
if (slots.default) {
state.tabs = slots.default().filter((child) => child.type.name === "Tab");
}
});
onMounted(() => {
selectTab(0);
});
return {...toRefs(state), selectTab};
}
});
</script>
Tab component:
<script lang="ts">
export default defineComponent({
name: "Tab",
setup() {
const index = ref(0);
const isActive = ref(false);
const tabs = inject("TabsProvider");
watch(
() => tabs.selectedIndex,
() => {
isActive.value = index.value === tabs.selectedIndex;
}
);
onBeforeMount(() => {
index.value = tabs.count;
tabs.count++;
isActive.value = index.value === tabs.selectedIndex;
});
return {index, isActive};
}
});
</script>
<template>
<div class="tab" v-show="isActive">
<slot></slot>
</div>
</template>
Oh guys, I solved it:
this.$slots.default().filter(child => child.type.name === 'Tab')
To someone wanting whole code:
Tabs.vue
<template>
<div>
<div class="tabs">
<ul>
<li v-for="tab in tabs" :class="{ 'is-active': tab.isActive }">
<a :href="tab.href" #click="selectTab(tab)">{{ tab.name }}</a>
</li>
</ul>
</div>
<div class="tabs-details">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "Tabs",
data() {
return {tabs: [] };
},
created() {
},
methods: {
selectTab(selectedTab) {
this.tabs.forEach(tab => {
tab.isActive = (tab.name == selectedTab.name);
});
}
}
}
</script>
<style scoped>
</style>
Tab.vue
<template>
<div v-show="isActive"><slot></slot></div>
</template>
<script>
export default {
name: "Tab",
props: {
name: { required: true },
selected: { default: false}
},
data() {
return {
isActive: false
};
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted() {
this.isActive = this.selected;
},
created() {
this.$parent.tabs.push(this);
},
}
</script>
<style scoped>
</style>
App.js
<template>
<Tabs>
<Tab :selected="true"
:name="'a'">
aa
</Tab>
<Tab :name="'b'">
bb
</Tab>
<Tab :name="'c'">
cc
</Tab>
</Tabs>
<template/>
If you copy pasted same code as me
then just add to the "tab" component a created method which adds itself to the tabs array of its parent
created() {
this.$parent.tabs.push(this);
},
My solution for scanning children elements (after much sifting through vue code) is this.
export function findChildren(parent, matcher) {
const found = [];
const root = parent.$.subTree;
walk(root, child => {
if (!matcher || matcher.test(child.$options.name)) {
found.push(child);
}
});
return found;
}
function walk(vnode, cb) {
if (!vnode) return;
if (vnode.component) {
const proxy = vnode.component.proxy;
if (proxy) cb(vnode.component.proxy);
walk(vnode.component.subTree, cb);
} else if (vnode.shapeFlag & 16) {
const vnodes = vnode.children;
for (let i = 0; i < vnodes.length; i++) {
walk(vnodes[i], cb);
}
}
}
This will return the child Components. My use for this is I have some generic dialog handling code that searches for child form element components to consult their validity state.
const found = findChildren(this, /^(OSelect|OInput|OInputitems)$/);
const invalid = found.filter(input => !input.checkHtml5Validity());
I made a small improvement to Ingrid Oberbüchler's component as it was not working with hot-reload/dynamic tabs.
in Tab.vue:
onBeforeMount(() => {
// ...
})
onBeforeUnmount(() => {
tabs.count--
})
In Tabs.vue:
const selectTab = // ...
// ...
watch(
() => state.count,
() => {
if (slots.default) {
state.tabs = slots.default().filter((child) => child.type.name === "Tab")
}
}
)
I had the same problem, and after doing so much research and asking myself why they had removed $children, I discovered that they created a better and more elegant alternative.
It's about Dynamic Components. (<component: is =" currentTabComponent "> </component>).
The information I found here:
https://v3.vuejs.org/guide/component-basics.html#dynamic-components
I hope this is useful for you, greetings to all !!
I found this updated Vue3 tutorial Building a Reusable Tabs Component with Vue Slots very helpful with explanations that connected with me.
It uses ref, provide and inject to replace this.tabs = this.$children; with which I was having the same problem.
I had been following the earlier version of the tutorial for building a tabs component (Vue2) that I originally found Creating Your Own Reusable Vue Tabs Component.
With script setup syntax, you can use useSlots: https://vuejs.org/api/sfc-script-setup.html#useslots-useattrs
<script setup>
import { useSlots, ref, computed } from 'vue';
const props = defineProps({
perPage: {
type: Number,
required: true,
},
});
const slots = useSlots();
const amountToShow = ref(props.perPage);
const totalChildrenCount = computed(() => slots.default()[0].children.length);
const childrenToShow = computed(() => slots.default()[0].children.slice(0, amountToShow.value));
</script>
<template>
<component
:is="child"
v-for="(child, index) in childrenToShow"
:key="`show-more-${child.key}-${index}`"
></component>
</template>
A per Vue documentation, supposing you have a default slot under Tabs component, you could have access to the slot´s children directly in the template like so:
// Tabs component
<template>
<div v-if="$slots && $slots.default && $slots.default()[0]" class="tabs-container">
<button
v-for="(tab, index) in getTabs($slots.default()[0].children)"
:key="index"
:class="{ active: modelValue === index }"
#click="$emit('update:model-value', index)"
>
<span>
{{ tab.props.title }}
</span>
</button>
</div>
<slot></slot>
</template>
<script setup>
defineProps({ modelValue: Number })
defineEmits(['update:model-value'])
const getTabs = tabs => {
if (Array.isArray(tabs)) {
return tabs.filter(tab => tab.type.name === 'Tab')
} else {
return []
}
</script>
<style>
...
</style>
And the Tab component could be something like:
// Tab component
<template>
<div v-show="active">
<slot></slot>
</div>
</template>
<script>
export default { name: 'Tab' }
</script>
<script setup>
defineProps({
active: Boolean,
title: String
})
</script>
The implementation should look similar to the following (considering an array of objects, one for each section, with a title and a component):
...
<tabs v-model="active">
<tab
v-for="(section, index) in sections"
:key="index"
:title="section.title"
:active="index === active"
>
<component
:is="section.component"
></component>
</app-tab>
</app-tabs>
...
<script setup>
import { ref } from 'vue'
const active = ref(0)
</script>
Another way is to make use of useSlots as explained in Vue´s documentation (link above).
Based on the answer of #Urkle:
/**
* walks a node down
* #param vnode
* #param cb
*/
export function walk(vnode, cb) {
if (!vnode) return;
if (vnode.component) {
const proxy = vnode.component.proxy;
if (proxy) cb(vnode.component.proxy);
walk(vnode.component.subTree, cb);
} else if (vnode.shapeFlag & 16) {
const vnodes = vnode.children;
for (let i = 0; i < vnodes.length; i++) {
walk(vnodes[i], cb);
}
}
}
Instead of
this.$root.$children.forEach(component => {})
write
walk(this.$root, component => {})
Many thanks #Urkle
In 3.x, the $children property is removed and no longer supported. Instead, if you need to access a child component instance, they recommend using $refs. as a array
https://v3-migration.vuejs.org/breaking-changes/children.html#_2-x-syntax

Move static parts of Vue code from methods() to <template>

Within my code there is some static data like const YAMAP_KEY and let src in the <script> section. I'd like to move those to the <template> section leaving the rest of the <script> section as is it now. How do I do it?
<template>
<div class='some-container container'>
<div id='yaMap'></div>
</div>
</template>
<script>
export default {
data: () => ({
}),
methods: {
loadYamap() {
return new Promise((resolve, reject) => {
const YAMAP_KEY = 'abcdef';
const YamapNode = document.createElement('script');
let src = 'https://api-maps.yandex.ru/2.1?lang=ru_RU&coordorder=longlat&apikey=' + YAMAP_KEY;
YamapNode.src = src;
YamapNode.onload = () => resolve();
YamapNode.onerror = (err) => {
console.log('map didn't load');
reject(err);
};
this.$el.appendChild(YamapNode);
});
}
},
mounted() {
this.loadYamap()
.then(() => {
ymaps.ready(() => {
var Yamap = new ymaps.Map('yaMap', {
center: [55.76, 37.64],
zoom: 10
})
})
})
.catch(ex => console.log('map load exception:', ex));
}
}
</script>
UP.
I've tried adding consts to the <template> section.
<template>
<div class='some-container container'>
<div id='yaMap'></div>
<script ref='myref'>
console.log('script in template');
const YAMAP_KEY = '8972y3uihfiuew';
let src = 'https://api-maps.yandex.ru/2.1?lang=ru_RU&coordorder=longlat';
<script>
</div>
</template>
Then accessing them in the <script> section.
<script>
export default {
data: () => ({
}),
methods: {
loadYamap() {
this.$refs.myref.onload = () => console.log('script in template loaded');
...
Add a tag inside and declare var for those constants and access them in your javascript code.
<div id="container">
<input type="text" id="container" placeholder="enter text" v-model="value">
<p>{{ value }}</p>
<script>var a = 'manu';</script>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.11.10/vue.min.js"></script>
<script>
new Vue({
el: '#container',
data: {
value: '',
},
created: function() {
console.log('Value', a);
}
});
</script>
Example: https://codepen.io/mnbhardwaj888/pen/PooPyjV

how to unittest a vuejs component update with methods using promise

I'm testing a Vue component with Jest. This is my working directory :
Here is my component Subscription.vue :
<template>
<div id="page">
<page-title icon="fa-list-alt">
<translate slot="title">Subscription</translate>
<translate slot="comment">Consult the detail of your subscription</translate>
</page-title>
<panel v-if="error">
<span slot="title">
<icon icon="fa-exclamation-triangle"></icon>
<translate>Error</translate>
</span>
{{ error }}
</panel>
<panel v-else-if="subscription_dict">
<span slot="title">{{ _subscription_address }}</span>
<div class="row" v-if="subscription_dict.product.hsi">
<div class="col-xs-12">
<subscription-hsi-panel
:hsi="subscription_dict.product.hsi"
:business="context.business">
</subscription-hsi-panel>
</div>
</div>
<div class="row" v-if="subscription_dict.product.itv">
<div class="col-xs-12">
<subscription-itv-panel
:itv="subscription_dict.product.itv">
</subscription-itv-panel>
</div>
</div>
<div class="row" v-if="subscription_dict.product.voip">
<div class="col-xs-6">
<panel icon="icon-voip">
<translate slot="title">Phone</translate>
telefon products
</panel>
</div>
</div>
</panel>
<div v-else class="text-center">
<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>
</div>
<span v-if="subscription_dict"><b>subscription_dict.product.voip : </b>{{ subscription_dict.product.voip }}</br></span>
<span v-if="subscription_dict"><b>subscription_dict.product : </b>{{ subscription_dict.product }}</br></span>
</div>
</template>
<script>
import PageTitle from '../../core/components/PageTitle.vue'
import SubscriptionHsiPanel from './SubscriptionHsiPanel.vue'
import SubscriptionItvPanel from './SubscriptionItvPanel.vue'
import Panel from '../../core/components/Panel.vue'
import Icon from '../../core/components/Icon.vue'
import api from '../../core/api.js'
export default {
data() {
return {
subscription_dict: false,
error: false
}
},
props: ['requests_url', 'context'],
computed: {
_subscription_address() {
var sub_address = this.subscription_dict.subscription_address
return sub_address + ' - ' + this.subscription_dict.package.join(' - ')
}
},
created() {
this.get_subscription()
this.translate()
},
methods: {
get_subscription() {
let self = this
api.get_subscription(self.requests_url.subscriptions_request)
.then(function(response) {
self.subscription_dict = response
})
.catch(function(error) {
if(error) {
self.error = error
} else {
self.error = self.$gettext(
'We were not able to retrieve your subscription information!')
}
})
},
translate() {
this.$gettext('Bridge hsi')
this.$gettext('Bridge voip_biz')
this.$gettext('Router')
}
},
components: {
PageTitle,
Panel,
Icon,
SubscriptionHsiPanel,
SubscriptionItvPanel
}
}
</script>
<style lang="sass">
#import "../../core/css/tooltip"
.table
table-layout: fixed
> tbody > tr >
th
width: 33%
td
vertical-align: middle
</style>
And here is my test subscription.js:
import Vue from 'vue'
import translations from 'src/translations.json'
import GetTextPlugin from 'vue-gettext'
import VTooltip from 'v-tooltip'
import Subscription from 'src/subscription/components/Subscription'
jest.mock('../../core/api');
Vue.use(GetTextPlugin, {
availableLanguages: {
en: 'English',
fr: 'Français',
de: 'Deutsch',
},
defaultLanguage: 'fr',
translations: translations
})
Vue.use(VTooltip)
it('render when error', (done) => {
const renderer = require('vue-server-renderer').createRenderer()
const vm = new Vue({
el: document.createElement('div'),
render: h => h(Subscription, {
props: {
requests_url: {
subscriptions_request: 'error_empty_promise'
}
}
})
})
renderer.renderToString(vm, (err, str) => {
setImmediate(() => {
expect(str).toMatchSnapshot()
done()
})
})
})
The component's method get_subscription() use my API function get_subscription:
import axios from 'axios'
export default {
get_subscription(url) {
return axios.get(url, {
credentials: 'same-origin'
})
.then(function(response){
if(response.data.error){
return Promise.reject(response.data.error)
}else{
return Promise.resolve(response.data)
}
})
.catch(function(error) {
return Promise.reject(false)
})
}
}
For my test, I have mocked this function like this :
const promises_object = {
error_empty_promise: new Promise((resolve, reject) => {
process.nextTick(
() => reject(false)
)
})
}
export default {
get_subscription(url) {
return promises_object[url]
}
}
Now, in the test I render and compare against a snapshot. My issue is, I can't find a way to wait that the promise of get_subscription is reject before making the comparison.
The result is that my snapshot reflect the state of the component before the update of the DOM, which is done after the asynchronous call on the API.
Is there a way to tell jest to wait until the Promise is reject before calling expect(str).toMatchSnapshot() ?
Jest docs say
it expects the return value to be a Promise that is going to be
resolved.
You have a promise that is going to be rejected, so you need a Promise that resolves when your promise is rejected.
isRejected(rejectingPromise, someExpects) {
return new Promise((resolve) => {
rejectingPromise.then(
() => null, // if it resolves, fail
(err) => { // if it rejects, resolve
// Maybe do someExpects() here
resolve();
}
});
}