I am struggling with stubbing third party elements with Sinon. Anybody seeing an issue here?
The funny thing is I am running pretty much the exact same test for a different module and it works.
I do admit I am not great on instantiation but really not seeing it.
Code to test
'use strict'
const { ActionRowBuilder, SelectMenuBuilder } = require('discord.js')
class Action {
static async selectHook (interaction, client, deleteId) {
const row = new ActionRowBuilder()
.addComponents(
new SelectMenuBuilder()
.setCustomId('confirmselect')
.setPlaceholder('Please confirm')
.addOptions(
{
label: 'I confirm',
description: `Confirm hook #${deleteId}`,
value: deleteId
}
)
)
await interaction.update({
content: 'Hook was selected! Please confirm ' +
'by using the select menu again.',
components: [row],
ephemeral: true
})
}
}
Test file
'use strict'
const sinon = require('sinon')
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
const sinonChai = require('sinon-chai')
chai.use(chaiAsPromised)
chai.use(sinonChai)
const expect = chai.expect
const { ActionRowBuilder, SelectMenuBuilder } = require('discord.js')
const client = {
once () {},
on () {},
},
const interaction = {
reply () {},
followUp () {},
update () {},
},
describe('app/Action', function () {
afterEach( function () {
sinon.restore()
})
describe('Action.selectHook', function () {
it(' should run interaction.update', async function () {
const updateStub = sinon.stub(interaction, 'update')
.resolves()
sinon.spy(function () {
return sinon.createStubInstance(ActionRowBuilder)
})
sinon.spy(function () {
return sinon.createStubInstance(SelectMenuBuilder)
})
await Action.selectHook(interaction, client, 1)
sinon.assert.calledOnceWithMatch(
updateStub,
{
content: 'Hook was selected! Please confirm ' +
'by using the select menu again.'
}
)
})
})
})
I have also tried with
sinon.createStubInstance(SelectMenuBuilder)
sinon.createStubInstance(ActionRowBuilder)
Anyways I get
1) should run interaction.update
0 passing (199ms)
1 failing
1) app/Action
Action.selectHook
should run interaction.update:
Error: Received one or more errors
at UnionValidator.handle (node_modules/#sapphire/shapeshift/dist/index.js:1085:23)
at UnionValidator.parse (node_modules/#sapphire/shapeshift/dist/index.js:142:88)
at /home/axel/Dropbox/0_Programming/discordjs-captain-hook/node_modules/#discordjs/builders/dist/index.js:557:147
at Array.map (<anonymous>)
at SelectMenuBuilder.addOptions (node_modules/#discordjs/builders/dist/index.js:557:34)
at SelectMenuBuilder.addOptions (node_modules/discord.js/src/structures/SelectMenuBuilder.js:48:18)
at Function.selectHook (app/Action.js:108:22)
at Context.<anonymous> (tests/mocha/Action.js:265:26)
at processImmediate (node:internal/timers:464:21)
Running on
Nodejs: v16.13.2
"discord-api-types": "^0.37.2",
"discord.js": "^14.2.0",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"mocha": "^10.0.0",
"nyc": "^15.1.0",
"sinon": "^14.0.0",
"sinon-chai": "^3.7.0"
Related
I am trying to test my contract in Mocha. and I am running into this issue where npm run test is giving the following result.
PiggyBank
1) "before each" hook for "is deployed"
0 passing (247ms)
1 failing
1) "before each" hook for "is deployed":
SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at Context.<anonymous> (test\PiggyBank.test.js:15:50)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
I tried searching on the web and making some tweaks but it didn't work.
Here is the contract PiggyBank.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract PiggyBank{
uint private pot;
//uint public input;
constructor (uint contribution){
// input = contribution;
pot = pot+contribution;
}
function peep () public view returns (uint) {
return pot;
}
function addToPot(uint contribution) public {
// input = contribution;
pot = pot + contribution;
}
}
Compile.js file given below
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const piggyBank = path.resolve(__dirname,'Contracts','PiggyBank.sol');
const source = fs.readFileSync(piggyBank,'utf8');
//console.log(solc.compile(source,1));
var input = {
language: 'Solidity',
sources: {
'PiggyBank.sol' : {
content: source
}
},
settings: {
outputSelection: {
'*': {
'*': [ '*' ]
}
}
}
};
console.log(JSON.parse(solc.compile(JSON.stringify(input))));
let output = JSON.parse(solc.compile(JSON.stringify(input)));
console.log(output.contracts['PiggyBank.sol']['PiggyBank'].abi);
console.log(output.contracts['PiggyBank.sol']['PiggyBank'].evm.bytecode.object);
module.exports = solc.compile(JSON.stringify(input));
package.json given below
{
"name": "piggybank",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC",
"dependencies": {
"ganache-cli": "^6.12.2",
"mocha": "^10.0.0",
"solc": "^0.8.17",
"web3": "^1.8.0"
}
}
PiggyBank.test.js file is given below
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());
const {interface, bytecode} = require('../compile');
let accounts;
let piggyBank;
beforeEach(async function(){
accounts = await web3.eth.getAccounts();
piggyBank = await new web3.eth.Contract(JSON.parse(interface)).deploy({data:bytecode,arguments:[20]}).
send({from: accounts[1], gas:10000})
});
describe('PiggyBank',function(){
it('is deployed',function(){
console.log(piggyBank);
});
});
Will deeply appreciate help on this issue. Thanks in advance.
Update
I updated the code to only export the interface and bytecode
following code update in Compile.js
const interface = output.contracts['PiggyBank.sol']['PiggyBank'].abi;
const bytecode = output.contracts['PiggyBank.sol']['PiggyBank'].evm.bytecode.object;
console.log(JSON.stringify(input))
module.exports = {interface,bytecode};
But now I am getting following error
1) "before each" hook for "is deployed"
0 passing (44ms)
1 failing
1) "before each" hook for "is deployed":
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
at Context.<anonymous> (test\PiggyBank.test.js:15:22)
at processImmediate (node:internal/timers:466:21)
It's having an issue parsing this part of code JSON.parse(interface)
piggyBank = await new web3.eth.Contract(JSON.parse(interface)).deploy({data:bytecode,arguments:[20]}).
send({from: accounts[1], gas:10000})
Thanks in advance
I need your help because it's the first time that I develop a Slack bot and I don't understand why this message appear:
const botSlack = new Slackbot ({
^
TypeError: Slackbot is not a constructor
Here my code : slack.js
const {Slackbot} = require('#slack/bolt');
const botSlack = new Slackbot({
token : process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
(async () => {
await botSlack.start(process.env.PORT || 3000);
})();
Part of my package.json:
"scripts": {
"dev": "nodemon slack.js",
},
"dependencies": {
"#slack/bolt": "^3.11.0",
},
In the bolt documentation (https://api.slack.com/tutorials/hello-world-bolt) and others, it's the same and it's run.
Please someone can explain to me why ?
The documentation has this code - App instead of Slackbot. You can rename the local variable if you want, but the import statement requires the exact name:
const { App } = require('#slack/bolt');
const botSlack = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
(async () => {
await botSlack.start(process.env.PORT || 3000);
})();
if you do want to rename the value, you can use
const { App: Slackbot } = require('#slack/bolt');
It is more common to use import statements for this, you can still alias it using import { App as Stackbot} from '#slack/bolt', see MDN - import
I'm having issues doing a unit test with the following environment:
"pubsub-js": "^1.9.2",
"#types/chai": "^4.2.14",
"#types/mocha": "^8.2.0",
"chai": "^4.2.0",
"firebase-functions-test": "^0.2.3",
"mocha": "^8.2.1",
"ts-node": "^9.1.1",
"ts-sinon": "^2.0.1",
When publish a message to my pubsub the data received by it is always: Message { data: undefined, attributes: {}, _json: undefined } and I can't figure out why.
There is some code to describe my scenario:
pubsub-myFunc.ts
export const pubsubMyFunc= functions.pubsub
.topic("on-myTopic")
.onPublish(async (message) => {
console.log("version 1")
console.log(message)
/**
* Received message from topic
*/
const myMessage = Buffer.from(message.data, "base64").toString("utf-8")
pubsub-myFunc.spec.ts
import * as functions from 'firebase-functions';
import * as PubSub from 'pubsub-js';
import * as tsSinon from 'ts-sinon';
import { pubsubMyFunc } from './pubsub-myFuncr';
import * as sendEmail from './send-mail';
describe("PubSub tests", () => {
beforeEach(() => {
process.env.GCLOUD_PROJECT = "my env"
})
it("Should call sendNotificationMessage", function (done) {
// this.timeout(60000)
const today = new Date()
const data = {
dateCreated: today,
expireDate: today.getDate() + 30,
objId: "id",
objParentId: "parentId",
}
const spy = tsSinon.default.spy(sendEmail, "sendNotificationMessage")
const dataBuffer = Buffer.from(JSON.stringify(data))
const pubsubMessage = new functions.pubsub.Message(dataBuffer)
PubSub.subscribe("on-myTopic", pubsubMyFunc)
console.log("publish")
PubSub.publish("on-myTopic", pubsubMessage)
setTimeout(() => {
// check if spy was called
tsSinon.default.assert.calledOnce(spy)
done()
}, 15000)
})
})
I have tried to pass directly the dataBuffer but without any luck as well, the outputs of my console logs are:
publish
version 1
Message { data: undefined, attributes: {}, _json: undefined }
Is there any reason for my Message.data to be undefined?
I'm not sure if pubsub-js's subscribe function is compatible with the output of firebase-functions' onPublish method.
You could use firebase's emulators to run your functions locally and test them by sending messages like you would normally instead of going through pubsub-js.
export const pubsubMyFunc= functions.pubsub
.topic("on-myTopic")
.onPublish(async (message) => {
console.log("version 1");
console.log(message);
/**
* Received message from topic
*/
const myMessage = message.json;
...
Make sure pubsubMyFunc is being exported at firebase functions entry point.
Install and configure firebase emulators, make sure PUBSUB_EMULATOR_HOST env var is set to localhost:$PORT where $PORT is set to the port you have configured for pub sub emulator, located in firebase.json under emulators.pubsub.port.
Once that's all setup, you can send a message to pubsub by:
import {PubSub} from "#google-cloud/pubsub";
cont getTopic = () => {
const topic = new PubSub().topic("on-myTopic");
topic.exists().then(([exists]) => exists
? topic
: topic.create().then(([newTopic]) => newTopic)
);
};
describe("PubSub tests", () => {
let topic;
beforeEach(async() => {
process.env.GCLOUD_PROJECT = "my env"
topic = await getTopic();
});
it("should test something", async() => {
await topic.publishJSON(const data = {
dateCreated: today,
expireDate: today.getDate() + 30,
objId: "id",
objParentId: "parentId",
});
// rest of your code here.
});
});
This will work on the process of hack
export const pubsubMyFunc= functions.pubsub
.topic("on-myTopic")
.onPublish(async (message) => {
console.log("version 1");
I am very new to jest and enzyme. In my Project I will use a SPA React based Application. Containing a Context Provider for the data, also several hooks. I Using now Jest (with ts-jest and enzyme)
My jest.config looks like this
module.exports = {
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"snapshotSerializers": ["enzyme-to-json/serializer"]
So my first stept so test UI components works.
Next step was to test componentes with mocked data. But there I got the error described at the bottom.
I have a functional component like this:
export default function CurrentWeather(props: ICurrentWeatherProps) {
const [data, Reload] = useCurrentWeather(props.locationID);
return (<div>......</div>)
}
You will notice the useCurrentWeather hook, here is the code for this:
import { useEffect, useState } from 'react';
import { useLocationState } from '../context/locationContext';
import { ILocationData } from './useLocations';
import _ from 'lodash';
...
export default function useCurrentWeater(locationId: number) {
const locationState = useLocationState();
const Reload = () => { GetData() }
const [Data, SetData] = useState<IWeatherDataInfo>({Id:0,ConditionIcon:'',Date:new Date(),MaxTemp:0, MinTemp:0});
async function GetData() { .... }
useEffect(Reload, [locationState.data, locationId]);
return [Data, Reload] as const;
}
Now I wand to mock these Hook. I tried following
import React from 'react';
import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import CurrentWeather from '../components/Weather/CurrentWeather';
import { IWeatherDataInfo } from '../Hooks/useWeaters';
configure({ adapter: new Adapter() });
const mockWeatherReload = jest.fn();
const mockdata: IWeatherDataInfo = { Date: new Date(), ConditionIcon: "", MinTemp: 0, MaxTemp: 10 };
jest.mock('../Hooks/useCurrentWeather', () => ({
useCurrentWeather: jest.fn(()=>{ [mockdata, mockWeatherReload]})
}));
describe("WeatherWidget", () => {
it("RenderOnlyAddButton", () => {
const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
});
});
Now, when I execute this test, I will get this error result:
src/tests/WeatherWidget.test.tsx
● WeatherWidget › RenderOnlyAddButton
TypeError: (0 , _useCurrentWeather.default) is not a function or its return value is not iterable
9 |
10 | export default function CurrentWeather(props: ICurrentWeatherProps) {
> 11 | const [data, Reload] = useCurrentWeather(props.locationID);
| ^
12 | return (
What I'm doing wrong here? Is there what I'm missing?
Try like this:(below should be your functional component's test file)
const mockUseCurrentWeather = jest.fn();
jest.mock("put here the absolute path", () => ({
__esModule: true,
useCurrentWeather: (...args: any) => mockUseCurrentWeather(...args),
}));
describe("WeatherWidget", () => {
beforeEach(() => {
mockUseCurrentWeather.mockClear();
mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
});
it("RenderOnlyAddButton", () => {
mockUseCurrentWeather.mockClear();
mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
});
});
Firebase - cloud firestore - unit testing fails with error
- TypeError: The "path" argument must be of type string.
Otherwise, it works fine when run with NodeJS command 'node index.js'
I use service account and NodeJS
myservice.js
var admin = require("firebase-admin");
var serviceAccount = require("./sakey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myapp.firebaseio.com"
});
const db = admin.firestore();
const getData = async () => {
const snapshot = await db.collection('users').get()
return snapshot.docs.map(doc => doc.data())
}
module.exports = { getData }
Test Case
const { getData } = require('./myservice')
describe('my test suite', () => {
it('Retrieve data', async () => {
let result = await getData();
return result().then(data => expect(data).toBeDefined())
}
}
Error
TypeError: The "path" argument must be of type string. Received type objectTypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
at GrpcClient.loadProto (node_modules/google-gax/src/grpc.ts:166:23)
at new FirestoreClient (node_modules/#google-cloud/firestore/build/src/v1/firestore_client.js:113:38)
at ClientPool.clientFactory (node_modules/#google-cloud/firestore/build/src/index.js:329:26)
at ClientPool.acquire (node_modules/#google-cloud/firestore/build/src/pool.js:87:35)
at ClientPool.run (node_modules/#google-cloud/firestore/build/src/pool.js:164:29)
at node_modules/#google-cloud/firestore/build/src/index.js:957:30
at Firestore._retry (node_modules/#google-cloud/firestore/build/src/index.js:822:38)
package.json
...
"dependencies": {
"dotenv": "^8.2.0",
"firebase-admin": "^8.10.0",
"moment": "^2.24.0"
},
"devDependencies": {
"#types/jest": "^25.1.4",
"jest": "^25.1.0"
}
...
According to this issue:
Adding a jest.config.js with the following code solved my issue
module.exports = {
testPathIgnorePatterns: ['lib/', 'node_modules/'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
testEnvironment: 'node'
};