Trying to test fetch with mocha & chai using await - javascript

I intend to test fatch with mocha. I am using testing fetch with mocha and chai
to get started but kept running into multiple errors.
Here is the test code:
var jsdom = require('mocha-jsdom')
global.document = jsdom();
const chai = require( 'chai' ).assert;
const fetch = require("node-fetch");
const chaiHTTP = require("chai-http");
const index = require('../client/js/index');
chai.should();
chai.use(chaiHTTP)
describe('Index', function(){
it( "renders book data ", async () =>{
await fetchBooks()
.then(() => {
expect(renderBooks).to.have.been.called();
})
})
})
This throws the following error :
TypeError: Cannot read property 'querySelector' of undefined
Probably the selector does not return any elements at the stage when the script is executed. Not sure why.
//index.js
function fetchBooks(){
fetch(`https://anapioficeandfire.com/api/books`)
.then(res => res.json())
.then(renderBooks)
}
const main = document.querySelector('#main')
function renderBooks(data) {
data.forEach(book => {
h2.innerHTML = `<h2>${book.name}</h2>`
})
}

Related

How to mock fs module together with unionfs?

I have written a test case that successfully load files into virtual FS, and at the same time mounted a virtual volume as below
describe("should work", () => {
const { vol } = require("memfs");
afterEach(() => vol.reset());
beforeEach(() => {
vol.mkdirSync(process.cwd(), { recursive: true });
jest.resetModules();
jest.resetAllMocks();
});
it("should be able to mock fs that being called in actual code", async () => {
jest.mock("fs", () => {
return ufs //
.use(jest.requireActual("fs"))
.use(createFsFromVolume(vol) as any);
});
jest.mock("fs/promises", () => {
return ufs //
.use(jest.requireActual("fs/promises"))
.use(createFsFromVolume(vol) as any);
});
const { createFsFromVolume } = require("memfs");
const { ufs } = require("unionfs");
const { countFile } = require("../src/ops/fs");
vol.fromJSON(
{
"./some/README.md": "1",
"./some/index.js": "2",
"./destination": null,
},
"/app"
);
const result = ufs.readdirSync(process.cwd());
const result2 = ufs.readdirSync("/app");
const result3 = await countFile("/app");
console.log({ result, result2, result3 });
});
});
By using ufs.readdirSync, I can access to virtual FS and indeed result giving me files that loaded from disc into virtual FS, result2 representing /app which is a new volume created from vol.fromJSON.
Now my problem is I am unable to get the result for result3, which is calling countFile method as below
import fsPromises from "fs/promises";
export const countFile = async (path: string) => {
const result = await fsPromises.readdir(path);
return result.length;
};
I'm getting error
Error: ENOENT: no such file or directory, scandir '/app'
which I think it's because countFile is accessing the actual FS instead of the virtual despite I've had jest.mock('fs/promises')?
Please if anyone can provide some lead?
This is the function you want to unit test.
//CommonJS version
const fsPromises = require('fs/promises');
const countFile = async (path) => {
const result = await fsPromises.readdir(path);
return result.length;
};
module.exports = {
countFile
}
Now, how you would normally go about this, is to mock fsPromises. In this example specifically readdir() since that is the function being used in countFile.
This is what we call: a stub.
A skeletal or special-purpose implementation of a software component, used to develop or test a component that calls or is otherwise dependent on it. It replaces a called component.
const {countFile} = require('./index');
const {readdir} = require("fs/promises");
jest.mock('fs/promises');
beforeEach(() => {
readdir.mockReset();
});
it("When testing countFile, given string, then return files", async () => {
const path = "/path/to/dir";
// vvvvvvv STUB HERE
readdir.mockResolvedValueOnce(["src", "node_modules", "package-lock.json" ,"package.json"]);
const res = await countFile(path);
expect(res).toBe(4);
})
You do this because you're unit testing. You don't want to be dependent on other functions because that fails to be a unit test and more integration test. Secondly, it's a third-party library, which is maintained/tested by someone else.
Here is where your scenario applies. From my perspective, your objective isn't to test countFile() rather, to test fsPromises and maybe test functionality to read virtual file-systems: unionfs. If so then, fsPromises doesn't need to really be mocked.

truffle - artifacts.require is not a function

I am currently learning solidity and creating my first project. I am trying to test the deployment of my contract with truffle and i keep getting the below error
TypeError: artifacts.reqiure is not a function
Syntax looks correct and there are no errors appearing. I have also gone into the truffle console and the migration seems to have deployed ok and Color.json is now in my abis folder as well.
Any help will be appreciated, all files are below.
Color.sol
pragma solidity 0.5.0;
import "./ERC721Full.sol";
contract Color is ERC721Full {
// Initialise function
constructor () ERC721Full("Color", "COLOR") public {
}
}
Color.test.js
const Color = artifacts.reqiure('./Color.sol')
require('chai')
.use(require('chai-as-promised'))
.should()
contract('Color', (accounts) => {
let contract
before(async () => {
contract = await Color.deployed()
})
describe('deployment,', async() => {
it('deploys successfully', async() => {
contract = await Color.deployed()
const address = contract.address
console.log(address)
assert.notEqual(address,"")
assert.notEqual(address, 0x0)
assert.notEqual(address, null)
assert.notEqual(address, undefined)
})
it('has a name', async () => {
const name = await contract.name()
assert.equal(name, 'Color')
})
it('has a symbol', async () => {
const symbol = await contract.symbol()
assert.equal(symbol, 'COLOR')
})
})
})
2_deploy_contracts.js
const Color = artifacts.require("Color");
module.exports = function(deployer) {
deployer.deploy(Color);
};
1_init_migration.js
const Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
Make sure you have
require('#nomiclabs/hardhat-truffle5');
Before you're trying to call artifacts.require
You have a typo in Color.test.js
const Color = artifacts.reqiure('./Color.sol')
should be require
I tried out this particular code and it shows out an error message and after looking into the line it is just a small spelling error in this particular line in the color code: -
const Color = artifacts.reqiure('./Color.sol')
Try replacing it with this: -
const Color = artifacts.require('./Color.sol')

How do I mock constructor state initialisation with Jest

New to node.js. I am writing a JS API client that wraps the underlying axios library. In the unit tests I am mocking axios using Jest.
In the constructor of my API class I pass in a URL, and use the axios.create function to create a custom instance of axios and bind it to the the client property.
The problem arises when I mock the axios dependency with jest.mock('axios') - A TypeError is being thrown in the test when an attempt is made to call axios.get:
TypeError: Cannot read property `get` of undefined
I understand why this is happening, but I've not found a way to enable me to mock axios and not have the client field be undefined. Is there a way to get around this, other than injecting axios through the constructor?
Client code and test below:
client.js
jest.mock("axios");
const axios = require("axios");
const mockdata = require("./mockdata");
const ApiClient = require("../../../src/clients/apiclient");
const BASE_URL = "https://www.mock.url.com"
const mockAxiosGetWith = mockResponse => {
axios.get.mockResolvedValue(mockResponse);
};
test("should make one get request", async () => {
mockAxiosGetWith(MOCK_RESPONSE)
// the client field in apiclient is undefined
// due to the jest module mocking of axios
const apiclient = new ApiClient.AsyncClient(BASE_URL);
// TypeError: Cannot read property `get` of undefined
return await apiclient.get("something").then(response => {
expect(axios.get).toHaveBeenCalledTimes(1);
});
});
client.test.js
const axios = require("axios");
const getClient = (baseUrl = null) => {
const options = {
baseURL: baseUrl
};
const client = axios.create(options);
return client;
};
module.exports = {
AsyncClient: class ApiClient {
constructor(baseUrl = null) {
this.client = getClient(baseUrl);
}
get(url, conf = {}) {
return this.client
.get(url, conf)
.then(response => Promise.resolve(response))
.catch(error => Promise.reject(error));
}
}
};
You need to mock axios so it will return an object which holds the create function which should return the object with the get
import axios from 'axios'
jest.mock('axios', () => ({create: jest.fn()}))
test("should make one get request", async () => {
const get = jest.fn(()=>Promise.resolve(MOCK_RESPONSE))
axios.create.mockImplementation(()=>({get}))
const apiclient = new ApiClient.AsyncClient(BASE_URL);
await apiclient.get("something")
expect(get).toHaveBeenCalledTimes(1);
});

Javascript Promise throws error using Mocha library

const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const inbox = require('../compile');
const web3 = new Web3(ganache.provider());
const interface = inbox.interface;
const bytecode = inbox.bytecode;
let contractAddress,inboxContract;
beforeEach(()=>{
// Get a list of all accounts
return web3.eth.getAccounts()
.then(accountList=>{
contractAddress = Array.from(accountList)[0];
return contractAddress;
})
.then(contractAddress=>{
inboxContract = new web3.eth.Contract(JSON.parse(interface))
.deploy({data: bytecode, arguments:['Hi there!']})
.send({from: contractAddress, gas: '1000000'});
return inboxContract;
})
//Use one of the accounts to deploy the contract
});
describe('Inbox contract test',()=>{
it('Successfully Deploy Test',()=>{
assert.ok(inboxContract.options.address);
})
it('Default Value test',()=>{
})
it('setMessage Test',()=>{
})
})
output-
I want beforeEach to execute completely before running it() block. Am I missing something here in Promise.
Ideally beforeEach() should complete before executing the test cases.
Screenshot-
the code for beforeEach should be inside of the describe and then you could use async - await instead of the standard promises which makes for a nicer syntax.
this would look like so
describe('Inbox contract test',()=>{
const inboxContract = new web3.eth.Contract(JSON.parse(interface))
beforeEach(async ()=>{
// Get a list of all accounts
const accountList = await web3.eth.getAccounts()
const contractAddress = Array.from(accountList)[0];
let receipt = await inboxContract.deploy({data: bytecode, arguments:['Hi there!']})
.send({from: contractAddress, gas: '1000000'});
//Use one of the accounts to deploy the contract
inboxContract.options.address = receipt.contractAddress
});
...
but you will have to make sure that your tests run inline because the global inboxContract variable will be replaced before each test
change your beforeEach block with following
beforeEach(() => {
return web3.eth.getAccounts()
.then(accountList => {
return Array.from(accountList)[0];
})
.then(account => {
contractAddress = account;
return new web3.eth.Contract(JSON.parse(interface))
.deploy({ data: bytecode, arguments: ['Hi there!'] })
.send({ from: account, gas: '1000000' });
})
.then(contract => {
inboxContract = contract;
})
});

Cannot read property of undefined thrown from running NPM and PACT

I'm trying to follow the PACT workshop example with some alternate data.
This may be more of a Javascript/Node question but I'm a but stumped, as a novice.
Given a consumer.spec.js file of:
const chai = require('chai');
const nock = require('nock');
const chaiAsPromised = require('chai-as-promised');
const expect = chai.expect;
const API_PORT = process.env.API_PORT || 9123;
chai.use(chaiAsPromised);
const API_HOST = `http://localhost:${API_PORT}`;
describe('Consumer', () => {
describe('when a call to the Provider is made', () => {
const clothingStatus = 'hello';
const {emailClothingOfferStatus} = require('../client');
it('can process the HTML payload from the provider', () => {
nock(API_HOST)
.get('/provider')
.query({validPermStatus:'hello'})
.reply(200, {
test:'NO',
validPermStatus: clothingStatus,
count: 1000,
});
const response = emailClothingOfferStatus(clothingStatus);
return expect(response.body.clothingStatus).to.eventually.equal('hello')
})
})
});
and a client .js file of:
const request = require('superagent');
const API_HOST = process.env.API_HOST || 'http://localhost';
const API_PORT = process.env.API_PORT || 9123;
const API_ENDPOINT = `${API_HOST}:${API_PORT}`;
// Fetch provider data
const emailClothingOfferStatus = emailPermChoice => {
let withEmailClothing = {};
const emailClothingGrantedRegex = 'hello';
if(emailPermChoice){
console.log(emailPermChoice);
withEmailClothing = {validPermStatus: emailPermChoice}
}
return request
.get(`${API_ENDPOINT}/provider`)
.query(withEmailClothing)
.then(
res => {
if (res.body.validPermStatus.match(emailClothingGrantedRegex)) {
return {
clothingStatus: (res.body.validPermStatus),
}
} else {
throw new Error('Could not verify email clothing offer status')
}
},
err => {
throw new Error(`Error from response: ${err.body}`)
}
)
};
module.exports = {
emailClothingOfferStatus,
};
and I have the following in my package.json scripts:
"test:consumer": "./node_modules/.bin/mocha --timeout 150000 pact/consumer/test/consumer.spec.js",
When I run npm run test:consumer, I get:
1) Consumer
when a call to the Provider is made
can process the HTML payload from the provider:
TypeError: Cannot read property 'clothingStatus' of undefined
at Context.it (pact/consumer/test/consumer.spec.js:29:35)
I'm sure it's something obvious but can anyone help?
Two things stand out to me as a problem:
The test above is a normal unit test designed to show how unit tests won't catch contract issues, and leads you into why Pact is useful (In case this wasn't clear). In short, it's not a Pact test at all - I can tell because it's using Nock, meaning the expected requests will never reach Pact. I can also tell because the Pact package doesn't appear to be imported. You want to model from this file https://github.com/DiUS/pact-workshop-js/blob/master/consumer/test/consumerPact.spec.js
The response value is a Promise, which means you can't do return expect(response.body.clothingStatus).to.eventually.equal('hello') because response is a promise, so body will be undefined and clothingStatus is not a property of that. The chai eventually API is useful for this sort of test, but as I understand, it has to work directly with a Promise - you could do expect(response).to... and then chai can go to work.
Your function emailClothingOfferStatus returns response.then() which is a promise and not an actual response.
Therefore response.body is undefined.
You should be able to test the result like this:
const response = emailClothingOfferStatus(clothingStatus);
response.then((res) => {
expect(res.body.clothingStatus).to.eventually.equal('hello')
})

Categories

Resources