Mocking a class in typescript with jest - class

I am trying to unit test (with Jest) my handler module that makes use of a summary class.
My original summary class looks like:
import DynamoDBClient from './ddbClient/DynamoDBClient'
import { DynamoDB } from 'aws-sdk'
import { iSummaryReader, iObsSummariesAttributes } from './Summary.d'
import { JSONAPIResource } from '../JSONAPIResponse'
export default class Summary {
reader: iSummaryReader
constructor(reader: iSummaryReader) {
this.reader = reader
}
getSummary = async (keyName: string, keyValue: string): Promise<JSONAPIResource<iObsSummariesAttributes>> => {
return new Promise<JSONAPIResource<iObsSummariesAttributes>>((resolve, reject) => {
const gettingItem = this.reader.getItem(keyName, keyValue)
console.log(gettingItem)
gettingItem.then((resp) => {
resolve(resp)
}).catch((err: Error) => {
reject(err.message)
})
})
}
}
In my handler module I import with import Summary from './lib/Summary'
(Note: same line is used in handler.test.ts
Inside the handler function
try {
const dynamodbObj: iSummaryReader = new DynamoDBClient(documentClient, someTable)
const summary = new Summary(dynamodbObj)
const data: JSONAPIResource<iObsSummariesAttributes> = await summary.getSummary('id', someID)
}
My results depend on my approach if try an automatic mock
jest.mock('./lib/Summary', () =>
{
return {
getSummary: jest.fn()
}
})
I get the error
TypeError: Summary_1.default is not a constructor
If I create a manual mock under lib/__mocks__/Summary.ts with jest.mock('./lib/Summary') it does work until I get the point
expect(Summary).toHaveBeenCalledTimes(1)
Where it complains about me not being able to do this on summary. I also am unable to access my method to test that they are being called this way.
Note: My hanlder is for a lambda function so I am unable to inject the class that way where I have successfully tested that I can mock an injected class.
EDIT
The tsconfig.json is:
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build",
"declaration": false,
"target": "es2015",
"moduleResolution": "node",
"module": "commonjs",
"noImplicitReturns": true,
"noImplicitThis": true,
"strictNullChecks": true,
"alwaysStrict": true,
"lib": [
"dom",
"es2015.promise",
"es2017.object",
"es2016"
],
},
"include": [
"src/**/*.ts"
],
}

I do not know why this was failing, but I the following steps seem to work to fix it.
Change the class export from default
From
`export default class Summary {`
to
`class summary`
+ export = summary at the end
Use import = require to import it.
import Summary = require('./lib/Summary')
Those two changes allowed it to find the jest.mock.

Related

Property 'start' does not exist on type 'ApolloServer'

I'm probably missing an obvious setting or something, but for some reason VS Code doesn't see ApolloServer.start, and I get an inline error:
Property 'start' does not exist on type 'ApolloServer'.
Can anyone see what I'm missing? It works by calling the usual listen method on the server, but I'm trying to add middleware, and this is the documented flow at apollo's official docs.
tsconfig
{
"compilerOptions": {
"baseUrl": ".",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"types": ["node"],
"esModuleInterop": true,
},
"include": [
"apollo-server/*"
],
"exclude": ["node_modules"]
}
index.ts
#!/usr/bin/env node
import express from 'express'
import { ApolloServer, gql } from 'apollo-server-express'
import { readFileSync } from 'fs'
import { resolvers } from './resolvers'
const typeDefs = gql`readFileSync('./schema.graphql').toString('utf-8')`
async function startServer() {
const server = new ApolloServer({
typeDefs,
resolvers,
})
await server.start() // <---- VSCode complains here
const app = express()
server.applyMiddleware({ app })
}
UPDATE
This question was regarding Apollo Server 2.0. The links have since been changed and Apollo is now on in version 3.0. If you're not dependent on version 2, I suggest updating your dependency to v3. For those of you stuck on this, here's the pattern:
// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({ typeDefs, resolvers });
// The `listen` method launches a web server.
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Here's a fresh URL to confirm it in the docs
FWIW, I found it right after I posted the question. This is a deprecated pattern. (Stale link removed)

i18n addResourceBundle mocks shows error i18n not defined

I am using react testing library to test my code and I have used i18n.addResourceBundle to add some translations on the fly. I am trying to test its and have
jest.mock('i18n', () => ({
__esModule: true,
default: { addResourceBundle: jest.fn() }
}))
BUt when I try to do snapshot, it keeps saying i18n.addResourceBundle is not defined
You are mocking i18next improperly.
The usage of i18next looks like:
import i18next from 'i18next';
export const i18n = i18next.init({
...
// config
...
});
// somewhere else in the code
i18n.addResourceBundle();
//-^ this is an instance of i18next
That means that you need to return an object with init function which returns an instance with addResourceBundle.
jest.mock('i18n', () => ({
__esModule: true,
default: {
init(config) {
return {
// this is the instance
addResourceBundle: jest.fn(),
};
},
},
}));

How to add a plugin in Aurelia

I am trying to use wavesurfer.js in an Aurelia project. I am not able to use the wavesurfer.js. After building it says Container Element not found.
my app.js looks like this
import * as wavesurfer from '../node_modules/wavesurfer/dist/wavesurfer.js';
export class App {
wavesurferObj = WaveSurfer.create({
container: '#waveform',
waveColor: 'violet',
progressColor: 'purple',
scrollParent: true,
});
constructor() {
wavesurferObj.load('http://ia902606.us.archive.org/35/items/shortpoetry_047_librivox/song_cjrg_teasdale_64kb.mp3');
wavesurferObj.on(ready, function () {
wavesurferObj.play();
});
}
}
and my main.js looks like this
// regenerator-runtime is to support async/await syntax in ESNext.
// If you target latest browsers (have native support), or don't use async/await, you can remove regenerator-runtime.
import * as wavesurfer from '../node_modules/wavesurfer/dist/wavesurfer.js';
// import * as timeline from '../node_modules/wavesurfer/plugin/wavesurfer.timeline.js';
// import * as regions from '../node_modules/wavesurfer/plugin/wavesurfer.regions.js';
import 'regenerator-runtime/runtime';
import * as environment from '../config/environment.json';
import {
PLATFORM
} from 'aurelia-pal';
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.feature(PLATFORM.moduleName('resources/index'));
aurelia.use.plugin(PLATFORM.moduleName('wavesurfer'));
// aurelia.use.plugin(PLATFORM.moduleName('timeline'));
// aurelia.use.plugin(PLATFORM.moduleName('regions'));
aurelia.use.developmentLogging(environment.debug ? 'debug' : 'warn');
if (environment.testing) {
aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
}
aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
}
and just the build section in Aurelia.json looks like this
"build": {
"options": {
"server": "dev",
"extractCss": "prod",
"coverage": false
},
"bundles": [{
"name": "vendor-bundle.js",
"dependencies": [{
"name": "wavesurfer",
"path": "../node_modules/wavesurfer/dist",
"main": "wavesurfer"
},
{
"name": "wavesurfer.timeline",
"path": "../node_modules/wavesurfer/plugin",
"main": "wavesurfer.timeline",
"deps": [
"wavesurfer"
]
},
{
"name": "wavesurfer.regions",
"path": "../node_modules/wavesurfer/plugin",
"main": "wavesurfer.regions",
"deps": [
"wavesurfer"
]
}
]
}]
},
Here is the error:
WaveSurfer is not defined.
Can someone indicate what is the right way to add this plugin please.
Thanks a lot in advance.
Without having a look at all of your actual code, i'm guessing you have at least 3 errors:
First one is using different variable names: wave surfer is imported as wavesurfer, but the way it's used is WaveSurfer, notice the case.
Using direct path to the dist file in a node_modules package:
import * as wavesurfer from '../node_modules/wavesurfer/dist/wavesurfer.js';
It should be:
import * as wavesurfer from 'wavesurfer';
3rd one is targeting an element via a CSS selector string #waveform. If this is not ready by the time you create an instance of class App, it will not work properly. Where is #waveform? from the document? from app.html? If it's from the document, it's ok, but if it's from app.html, you will need to change that code to something like this
<template>
....
<div ref="waveformElement"></div>
</template>
And in your app code:
import * as WaveSurfer from 'wavesurfer';
export class App {
bind() {
this.wavesurferObj = WaveSurfer.create({
container: this.waveformElement,
waveColor: 'violet',
progressColor: 'purple',
scrollParent: true,
});
this.wavesurferObj.load( 'http://ia902606.us.archive.org/35/items/shortpoetry_047_librivox/song_cjrg_teasdale_64kb.mp3');
this.wavesurferObj.on(ready, () => {
this.wavesurferObj.play();
});
}
}

Nuxt.js - Implementing a component using Plugin

I would like to implement a custom Toaster component into my NuxtJs application by this method this.$toast.show({}) What is the best way of approaching this? Sadly I can't find any documentation on this.
Sorry, I arrive one year late...
I had the same proplem. Here is my code:
The index of my plugin (index.js ; Nofification.vue is a classical Vue component):
import Notifications from './Notifications.vue'
const NotificationStore = {
state: [], // here the notifications will be added
settings: {
overlap: false,
horizontalAlign: 'center',
type: 'info',
timeout: 5000,
...
},
setOptions(options) {
this.settings = Object.assign(this.settings, options)
},
removeNotification(timestamp) {
...
},
addNotification(notification) {
...
},
notify(notification) {
...
},
}
const NotificationsPlugin = {
install(Vue, options) {
const app = new Vue({
data: {
notificationStore: NotificationStore,
},
methods: {
notify(notification) {
this.notificationStore.notify(notification)
},
},
})
Vue.prototype.$notify = app.notify
Vue.notify = app.notify
Vue.prototype.$notifications = app.notificationStore
Vue.component('Notifications', Notifications)
if (options) {
NotificationStore.setOptions(options)
}
},
}
export default NotificationsPlugin
Here I call my plugin and inject it in Nuxt:
import Notifications from '~/components/NotificationPlugin'
Vue.use(Notifications)
export default (context, inject) => {
inject('notify', Vue.notify)
}
In my case, I use it in another plugin (nuxtjs axios).
import NOTIFICATIONS from '~/constants/notifications'
export default function ({ error, $axios, app }) {
// Using few axios helpers (https://axios.nuxtjs.org/helpers):
$axios.onError((axiosError) => {
// eslint-disable-next-line no-console
console.log('Axios: An error occured! ', axiosError, axiosError.response)
if (process.server) {
...
} else {
app.$notify({
message: 'Mon message',
timeout: NOTIFICATIONS.DEFAULT_TIMEOUT,
icon: 'tim-icons icon-spaceship',
horizontalAlign: NOTIFICATIONS.DEFAULT_ALIGN_HORIZONTAL,
verticalAlign: NOTIFICATIONS.DEFAULT_ALIGN_VERTICAL,
type: 'success',
})
console.log('PRINT ERROR')
return Promise.resolve(true)
}
})
}
As I injected it, I think I could have done export default function ({ error, $axios, app, $notify }) { and directly use $notify (and not the app.$notify).
If you want a better understanding, feel free to consult #nuxtjs/toast which works the same way:
https://github.com/nuxt-community/community-modules/blob/master/packages/toast/plugin.js
And the matching Vue component:
https://github.com/shakee93/vue-toasted/blob/master/src/index.js
Good luck, this is not easy stuff. I'll try to add something easier to understand in the docs!
you can find in this package https://www.npmjs.com/package/vue-toasted
installation
npm install vue-toasted --save
make a file as name toast.js in plugin folder
toast.js
import Vue from 'vue';
import Toasted from 'vue-toasted';
Vue.use(Toasted)
add this plugin to nuxt.config.js
plugins: [
{ src: '~/plugins/toast', ssr: false },
],
now you able to use in your methods like this
this.$toasted.show('hello i am your toast')
hope this helps

How can we use the On Prepare function in config File while i am trying to run multiple Spec files

In the Config File i am using the On Prepare Function for the purpose of assigning the property data test id as value
But for the first spec file execution the on prepare is picked up
but on the next execution of the Spec , the on prepare function is not getting picked up
import { Config } from "protractor/built/config";
import { by } from "protractor";
// import { encode } from "punycode";
function encode(file) {
var stream = require('fs').readFileSync(file);
return new Buffer(stream).toString('base64');
}
export let config: Config = {
// The address of a running selenium server.
//seleniumAddress: 'http://localhost:4444/wd/hub',
directConnect:true,
allScriptsTimeout:1500000,
// Capabilities to be passed to the webdriver instance.
capabilities: {
browserName: 'chrome',
'chromeOptions': {
'extensions': [encode('C:/Users/koanand/Documents/Protractor/ASR/2.2.9_0.crx')]
}
},
onPrepare: function () {
by.addLocator('testId', function(value, parentElement) {
parentElement = parentElement || document;
var nodes = parentElement.querySelectorAll('[data-test-id]');
return Array.prototype.filter.call(nodes, function(node) {
return (node.getAttribute('data-test-id') === value);
});
});
},
// Spec patterns are relative to the configuration file location passed
// to protractor (in this example conf.js).
// They may include glob patterns.
specs: ['C:/Users/anand/Documents/Protractor/ASR/TS-Output/specs/directasr.js',
'C:/Users/anand/Documents/Protractor/ASR/TS-Output/specs/products.js'
],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true, // Use colors in the command line report.
defaultTimeoutInterval : 150000
}
};
i am observing the below error
Message:
Failed: protractor_1.by.testID is not a function
Stack:
TypeError: protractor_1.by.testID is not a function
at new productlist (C:\Users\koanand\Documents\Protractor\ASR\pageobject\productlist.ts:19:45)
at product.selectingproductlist (C:\Users\koanand\Documents\Protractor\ASR\specs\classproductlist.ts:14:32)
at UserContext.<anonymous> (C:\Users\koanand\Documents\Protractor\ASR\specs\products.ts:21:21)
at C:\Users\koanand\Documents\Protractor\ASR\node_modules\jasminewd2\index.js:108:15
at new ManagedPromise (C:\Users\koanand\Documents\Protractor\ASR\node_modules\selenium-webdriver\lib\promise.js:1077:7)
at ControlFlow.promise (C:\Users\koanand\Documents\Protractor\ASR\node_modules\selenium-webdriver\lib\promise.js:2505:12)
at schedulerExecute (C:\Users\koanan
d\Docume
Use BeforeAll() in each spec file & write whatever you want to execute before each spec starts
May following link help you to clear your doubts for onPrepare and what to use in pace of it.
OnPrepare function in Protractor