Push notifications when the Electron app is turned off - javascript

My electron app is using the remote isolation approach (mentioned in this article). My remote web app is a Ruby on Rails app. Now, I want to push notifications from a remote web app to the electron app using WebSocket. To send the message to users even if they shut off the app, I got an idea. In the Rails server, I use ActionCable to broadcast the notifications to a channel. In the main process, I subscribe to this channel by using the actioncable package.
import ActionCable from "actioncable";
const websocketUrl = "wss://rt.custom-domain.dev/_/cable";
const cable = ActionCable.createConsumer(websocketUrl);
cable.subscriptions.create(
{ channel: "WallChannel", wall_id: "106" },
{
received(data: any): void {},
disconnect(): void {},
connected(): void {},
disconnected(): void {},
present(): void {},
absent(): void {},
}
);
But I got an error:
ReferenceError: window is not defined
Then I dive deep into the source code of the actioncable package and I found that the package using WebSocket API of the browser so that why the error appeared.
I tried to use ws package to subscribe to the websocket instead by following this post. But I couldn't connect to the websocket server. When I call App.ws.sendmessage I got an error:
Error: WebSocket is not open: readyState 0 (CONNECTING)
Has anyone tried to push notifications from the remote web app by using websocket like what I've trying? Did you got the same problem? or If you got a better solution for my case, please share with me your idea. Thanks a lot.
This is my main.ts file of the electron app
import { app, BrowserWindow, ipcMain, Notification } from "electron";
import { createWindow } from "src/main/CreateWindow";
import { showNotification } from "./helpers";
import appConfigs from "src/AppConfigs";
let mainWindow: BrowserWindow;
const createAppWindow = () => {
mainWindow = createWindow(appConfigs.targetUrl, { interop: true });
// Open the DevTools.
if (!app.isPackaged) {
mainWindow.webContents.openDevTools();
}
};
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
// eslint-disable-line global-require
app.quit();
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", () => {
createAppWindow();
});
var App: { ws: any; param: any; connect_server: any; sendmessage: any } = {
ws: null,
param: null,
connect_server: () => {},
sendmessage: () => {},
};
App.sendmessage = function (send: any) {
let data = {
message: send,
action: "speak",
};
let message = {
command: "message",
identifier: JSON.stringify(App.param),
data: JSON.stringify(data),
};
App.ws.send(JSON.stringify(message));
};
App.connect_server = function () {
const WebSocket = require("ws");
App.ws = new WebSocket("wss://rt.custom-domain.dev/_/cable", [
"actioncable-v1-json",
"actioncable-unsupported",
]);
console.log("connect_server", App.ws);
App.param = { channel: "WallChannel", wall_id: 106 };
App.ws.on("open", function open() {
console.log("open channel");
let data = {
command: "subscribe",
identifier: JSON.stringify(App.param),
};
App.ws.send(JSON.stringify(data));
console.log("send JSON");
});
App.ws.on("message", function (event: any) {
console.log("message", event);
});
App.ws.on("error", function (err) {
console.log("Found error: " + err);
});
};
App.connect_server();
CreateWindow.ts
import { BrowserWindow } from "electron";
import appConfigs from "src/AppConfigs";
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: any;
interface BrowserWindowOption {
title?: string;
height?: string;
width?: string;
interop?: boolean;
}
export const createWindow = (
url: string,
options: BrowserWindowOption = {}
): BrowserWindow => {
// Create the browser window.
const mainWindow = new BrowserWindow({
title: options.title || appConfigs.name,
height: options.height || appConfigs.height,
width: options.width || appConfigs.width,
webPreferences: options.interop
? {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
}
: {},
});
// and load the targetUrl.
mainWindow.loadURL(url || appConfigs.targetUrl);
return mainWindow;
};
package.json
{
"name": "electron-forge-app",
"productName": "electron-forge-app",
"version": "1",
"description": "My Electron application description",
"main": ".webpack/main",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts ."
},
"keywords": [],
"author": {
...
},
"license": "MIT",
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "#electron-forge/maker-squirrel",
"config": {
"name": "electron_furge"
}
},
{
"name": "#electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "#electron-forge/maker-deb",
"config": {}
},
{
"name": "#electron-forge/maker-rpm",
"config": {}
}
],
"plugins": [
[
"#electron-forge/plugin-webpack",
{
"mainConfig": "./webpack.main.config.js",
"renderer": {
"config": "./webpack.renderer.config.js",
"entryPoints": [
{
"html": "./src/index.html",
"js": "./src/renderer.ts",
"name": "main_window",
"preload": {
"js": "./src/interop/preload.ts"
}
}
]
}
}
]
]
}
},
"devDependencies": {
"#electron-forge/cli": "^6.0.0-beta.54",
"#electron-forge/maker-deb": "^6.0.0-beta.54",
"#electron-forge/maker-rpm": "^6.0.0-beta.54",
"#electron-forge/maker-squirrel": "^6.0.0-beta.54",
"#electron-forge/maker-zip": "^6.0.0-beta.54",
"#electron-forge/plugin-webpack": "6.0.0-beta.54",
"#marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
"#types/actioncable": "^5.2.4",
"#typescript-eslint/eslint-plugin": "^4.0.1",
"#typescript-eslint/parser": "^4.0.1",
"css-loader": "^4.2.1",
"electron": "12.0.5",
"eslint": "^7.6.0",
"eslint-plugin-import": "^2.20.0",
"fork-ts-checker-webpack-plugin": "^5.0.14",
"node-loader": "^1.0.1",
"style-loader": "^1.2.1",
"ts-loader": "^8.0.2",
"typescript": "^4.0.2"
},
"dependencies": {
"actioncable": "^5.2.6",
"electron-squirrel-startup": "^1.0.0",
"ws": "^7.4.5"
}
}

Related

Jest error while trying to use with the file-type module. How can I fix "Cannot use import statement outside a module"?

Hi im trying to create tests for my code and i got a problem, the main message on terminal is:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest).
{import * as strtok3 from 'strtok3';
^^^^^^
SyntaxError: Cannot use import statement outside a module
looks that one of my dependencies is unable to work with jest, maybe cause im using typescript. Someone knows how can i fix that? I let all necessary info about my project, including the error on terminal, above. Thank you.
File that im testing:
import {
S3Client,
PutObjectCommand,
PutObjectCommandInput,
} from "#aws-sdk/client-s3";
import { v4 as uuidv4 } from "uuid";
import { fileTypeFromBuffer } from "file-type";
import { MulterFile } from "../../../types/MulterFile";
import { createImageInDB } from "../create-in-db";
const client = new S3Client({
region: "sa-east-1",
credentials: {
accessKeyId: process.env.AWS_IAM_IMAGES_ACCESS_KEY!,
secretAccessKey: process.env.AWS_IAM_IMAGES_SECRET_KEY!,
},
});
// export const UploadFileSchema = z.object({
// file: z.instanceof(),
// });
// export type UploadFileType = z.infer<typeof UploadFileSchema>;
export const verifyFileTypeIsCorrect = async (
types: string[],
file: MulterFile
) => {
const fileType = await fileTypeFromBuffer(file.buffer);
if (!fileType) {
return false;
}
if (types.includes(fileType.ext)) {
return `.${fileType.ext}`;
}
return false;
};
const acceptedFileTypes = ["jpeg", "png", "jpg", "webp"];
export const uploadImage = async ({
file,
path,
userId,
}: {
file: MulterFile;
path: string;
userId?: string | null;
}) => {
const fileType = await verifyFileTypeIsCorrect(acceptedFileTypes, file);
if (!fileType) {
return {
success: false,
message: `Tipo de arquivo inválido, aceitamos apenas: ${acceptedFileTypes.join(
", "
)}`,
};
}
const newFileName =
`${path}/${userId ? userId + "/" : ""}` + uuidv4() + fileType;
const uploadParams: PutObjectCommandInput = {
Bucket: process.env.AWS_IAM_IMAGES_BUCKET_NAME!,
Key: newFileName,
Body: file.buffer,
};
let output;
try {
output = await client.send(new PutObjectCommand(uploadParams));
} catch (error) {
return {
success: false,
message: "Erro ao fazer upload da imagem.",
};
}
const url = `https://${process.env.AWS_IAM_IMAGES_BUCKET_NAME}.s3.sa-east-1.amazonaws.com/${newFileName}`;
return {
success: true,
message: "Upload feito com sucesso.",
data: {
url,
},
};
};
export const uploadImageAndCreateInDB = async ({
file,
path,
userId,
alt,
name,
}: {
file: MulterFile;
path: string;
userId: string;
alt?: string;
name?: string;
}) => {
const {
data: dataUpload,
message: messageUpload,
success: successUpload,
} = await uploadImage({ file, path, userId });
if (!successUpload || !dataUpload) {
throw new Error(messageUpload);
}
const { data, message, success } = await createImageInDB({
url: dataUpload.url,
alt,
userId,
name,
});
if (!success || !data) {
throw new Error(message);
}
return {
success: true,
message: "Upload feito com sucesso.",
data,
};
};
jest.config.js
module.exports = {
clearMocks: true,
preset: "ts-jest",
testEnvironment: "node",
setupFilesAfterEnv: ["./singleton.ts"],
};
package.json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "prisma generate",
"test": "NODE_ENV=test jest -i --verbose"
},
"dependencies": {
"#aws-sdk/client-s3": "^3.238.0",
"#bmunozg/react-image-area": "^1.1.0",
"#headlessui/react": "^1.7.7",
"#heroicons/react": "^2.0.13",
"#next-auth/prisma-adapter": "^1.0.5",
"#nivo/bar": "^0.80.0",
"#nivo/core": "^0.80.0",
"#nivo/line": "^0.80.0",
"#prisma/client": "^4.8.0",
"#sendgrid/mail": "^7.7.0",
"#stripe/stripe-js": "^1.46.0",
"#tanstack/react-query": "^4.20.4",
"#trpc/client": "^10.7.0",
"#trpc/next": "^10.7.0",
"#trpc/react-query": "^10.7.0",
"#trpc/server": "^10.7.0",
"#types/node": "18.11.9",
"#types/react": "18.0.25",
"bcrypt": "^5.1.0",
"blaze-slider": "^1.9.0",
"cookies": "^0.8.0",
"daisyui": "^2.46.0",
"eslint": "8.27.0",
"eslint-config-next": "^13.1.1",
"file-type": "^18.0.0",
"jsonwebtoken": "^9.0.0",
"lodash": "^4.17.21",
"micro": "^9.4.1",
"micro-cors": "^0.1.1",
"multer": "^1.4.5-lts.1",
"next": "^13.1.1",
"next-auth": "^4.18.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-toastify": "^9.1.1",
"sanitize-html": "^2.8.1",
"stripe": "^11.5.0",
"uuid": "^9.0.0",
"zod": "^3.20.2"
},
"devDependencies": {
"#tailwindcss/typography": "^0.5.8",
"#types/bcrypt": "^5.0.0",
"#types/cookies": "^0.7.7",
"#types/jest": "^29.2.4",
"#types/jsonwebtoken": "^8.5.9",
"#types/lodash": "^4.14.191",
"#types/micro-cors": "^0.1.2",
"#types/multer": "^1.4.7",
"#types/react-dom": "^18.0.10",
"#types/sanitize-html": "^2.8.0",
"#types/uuid": "^8.3.4",
"autoprefixer": "^10.4.13",
"jest": "^29.3.1",
"jest-mock-extended": "^3.0.1",
"postcss": "^8.4.20",
"prisma": "^4.8.0",
"tailwindcss": "^3.2.4",
"ts-jest": "^29.0.3",
"typescript": "^4.9.4"
}
index.test.ts file:
import {
uploadImage,
verifyFileTypeIsCorrect,
} from "../../../src/lib/services/image/upload";
import { OBJECT_TO_MOCK_USER } from "../auth/index.test";
export const OBJECT_TO_MOCK_IMAGE = () => ({
id: "clbfokijd00007z6bsf3qgq5t",
url: `https://${process.env.AWS_IAM_IMAGES_BUCKET_NAME}.s3.sa-east-1.amazonaws.com/texts/clbfp20sl00097z6bnuptsu8f/b49afd22-337b-43e9-811c-d70c551c4086.jpg`,
name: "Teste Nome",
});
jest.mock("#aws-sdk/client-s3", () => {
return {
S3Client: jest.fn(() => ({
send: jest.fn(() => ({
success: true,
message: "Upload feito com sucesso.",
data: {
url: `https://${process.env.AWS_IAM_IMAGES_BUCKET_NAME}.s3.sa-east-1.amazonaws.com/texts/clbfp20sl00097z6bnuptsu8f/b49afd22-337b-43e9-811c-d70c551c4086.jpg`,
},
})),
})),
};
});
jest.mock("uuid", () => {
return {
v4: jest.fn(() => "b49afd22-337b-43e9-811c-d70c551c4086"),
};
});
describe("Image", () => {
let image: any;
let user: any;
beforeEach(async () => {
image = OBJECT_TO_MOCK_IMAGE();
user = OBJECT_TO_MOCK_USER("123456789");
});
test("deve verificar se os tipos do arquivo são válidos", async () => {
const file = {
mimetype: "application/pdf",
buffer: Buffer.from(""),
originalname: "teste.pdf",
};
const acceptedFileTypes = ["jpeg", "png", "jpg", "webp"];
await expect(
verifyFileTypeIsCorrect(acceptedFileTypes, file)
).resolves.toEqual({
success: false,
message: `Tipo de arquivo inválido, aceitamos apenas: ${acceptedFileTypes.join(
", "
)}`,
});
});
test("verify uploadImage function que deve fazer upload de uma imagem", async () => {
const file = {
mimetype: "image/jpeg",
buffer: Buffer.from(""),
originalname: "teste.jpeg",
};
await expect(
uploadImage({
file,
path: "teste",
userId: user.id,
})
).resolves.toEqual({
success: true,
message: "Upload feito com sucesso.",
data: {
url: `https://${process.env.AWS_IAM_IMAGES_BUCKET_NAME}.s3.sa-east-1.amazonaws.com/teste/${user.id}/b49afd22-337b-43e9-811c-d70c551c4086.jpg`,
},
});
});
});
Console Error:
FAIL tests/api/image/index.test.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/test/Dev/next/node_modules/file-type/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as strtok3 from 'strtok3';
^^^^^^
SyntaxError: Cannot use import statement outside a module
5 | } from "#aws-sdk/client-s3";
6 | import { v4 as uuidv4 } from "uuid";
> 7 | import { fileTypeFromBuffer } from "file-type";
| ^
8 | import { MulterFile } from "../../../types/MulterFile";
9 | import { createImageInDB } from "../create-in-db";
10 |
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1449:14)
at Object.<anonymous> (src/lib/services/image/upload/index.ts:7:1)
at Object.<anonymous> (tests/api/image/index.test.ts:4:1)
According to another post on stackoverflow: "Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6
You can add
"type": "module",
to your package.json.
Hope this helps!

Capacitor / Cordova EmmAppConfig plugin with Javascript

I'm trying to get the following working based on this post "Building a CapacitorJS application using pure JavaScript and Webpack" on Medium.com (https://medium.com/#SmileFX/a-complete-guide-building-a-capacitorjs-application-using-pure-javascript-and-webpack-37d00f11720d)
My intention is to build an Android app that will get deployed from an MDM server with an AppConfig configuration. When launched, the app will generate a file (derived from the AppConfig configuration) and save the file to the file system on the device.
Here is the content of my index.js
import '#capacitor/core';
import '#angular/core';
import '#ionic-native/core';
import 'rxjs';
import { Device } from '#capacitor/device';
import { Filesystem, Directory, Encoding } from '#capacitor/filesystem';
//import { EmmAppConfig } from '#ionic-native/emm-app-config/ngx';
async function getDeviceInfo() {
message("getDeviceInfo started");
let info = await Device.getInfo();
return info.operatingSystem;
}
async function getEmmAppConfig() {
message("getEmmAppConfig started");
//let eac = await EmmAppConfig.getValue("z_number");
let eac = "Z_1234_567";
return eac;
};
async function putFile(name, data) {
message("putFile started with name: " +name+ " and data: " +data);
let file = await Filesystem.writeFile({
path: "file:///storage/emulated/0/z_number/" +name+ ".txt",
data: data,
recursive: true,
encoding: Encoding.UTF8
});
return file;
};
window.onload = start;
function start() {
message("app started");
getDeviceInfo().then(info => {
putFile("info", info).then(file => {
message("File saved here: " +JSON.stringify(file, null, 4));
});
});
getEmmAppConfig().then(eac => {
putFile("eac", eac).then(file => {
message("File saved here: " +JSON.stringify(file, null, 4));
});
});
}
function message(message) {
document.body.innerHTML = document.body.innerHTML+ "<p>" +message+ "</p>" ;
}
The above code does run on the Android emulator and saves bothe files as expected only when "import { EmmAppConfig } from '#ionic-native/emm-app-config/ngx';" is commented out, otherwise it does not run (not even to output "App Started")
this is the content of my package.json
{
"name": "capacitor-app",
"version": "1.0.0",
"description": "An Amazing Capacitor App",
"main": "index.js",
"keywords": [
"capacitor",
"mobile"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"#angular/core": "^13.0.3",
"#capacitor/android": "^3.3.2",
"#capacitor/camera": "latest",
"#capacitor/core": "latest",
"#capacitor/device": "^1.1.0",
"#capacitor/filesystem": "^1.0.6",
"#capacitor/splash-screen": "latest",
"#ionic-native/core": "^5.36.0",
"#ionic-native/emm-app-config": "^5.36.0",
"cordova-plugin-emm-app-config": "^1.0.2",
"rxjs": "^7.4.0"
},
"devDependencies": {
"#capacitor/cli": "latest",
"webpack-cli": "^4.9.1"
},
"author": "",
"license": "ISC"
}
What am i missing?

redis port and host undefined even though env are set

I am using the redis npm package and whenever I try to connect to it, it's saying the host and port are undefined. I print out my process.env object and I can see that the host and port have values set. It's only when I pass the values into my constructor for my Redis model class, that it becomes undefined. Any ideas?
index.js
require('dotenv').config()
function startRedis() {
const redisInstance = new Redis(
process.env.REDIS_HOST,
process.env.REDIS_PORT
);
redisInstance.init();
}
class Redis {
constructor(redishost, redisport) {
this.redishost = redishost;
this.redisport = redisport;
}
async init() {
try {
this.redisClient = redis.createClient({
port: this.redisport,
host: this.redishost
});
console.log("port: ", this.port)
console.log("host: ", this.host)
} catch(error) {
console.log(`Error creating client due to: ${error}`)
}
}
.env
REDIS_HOST="value here"
REDIS_PORT="port value here"
package.json
{
"name": "app",
"version": "0.0.1",
"dependencies": {
"redis": "^3.0.2",
"dotenv": "^10.0.0"
},
"engines": {
"node": ">=10.0.0"
},
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"redis": "^3.0.2",
"dotenv": "^10.0.0"
}
}
Update 1: Added my package.json
As I can see here if process.env.REDIS_HOST having value.
You have new on wrong class name
Your start function should be like
function startRedis() {
const redisInstance = new Redis(
process.env.REDIS_HOST,
process.env.REDIS_PORT
);
redisInstance.init();
}
And you are console.log wrong value
class Redis {
constructor(redishost, redisport) {
this.redishost = redishost;
this.redisport = redisport;
}
async init() {
try {
this.redisClient = redis.createClient({
port: this.redisport,
host: this.redishost
});
console.log("port: ", this.redisport)
console.log("host: ", this.redishost)
} catch(error) {
console.log(`Error creating client due to: ${error}`)
}
}

Cannot get response from getStateByPartialCompositeKey

I cannot obtain a response from the getStateByPartialCompositeKey method. I can use putState and getState just fine, but cannot use getStateByPartialCompositeKey. I'm using NodeJS fabric-contract-api version of Fabric's chaincode.
For the development, I used this commercial-paper example. This example uses the test-network environment, which is working just fine.
This implementation offers some ledger API utility classes that I'm using also to interact with the ledger. It has two classes, state.js and stateList.js I added a method to stateliest called getAllStatesFromPartialCompositeKey to try and use getStateByPartialCompositeKey method.
Package.json
{
"name": "informed-consent-form-contract",
"version": "0.0.5",
"description": "Papernet Contract",
"main": "index.js",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "nyc mocha test --recursive",
"start": "fabric-chaincode-node start",
"mocha": "mocha test --recursive"
},
"engineStrict": true,
"author": "hyperledger",
"license": "Apache-2.0",
"dependencies": {
"axios": "^0.19.2",
"fabric-contract-api": "^2.0.0",
"fabric-shim": "^2.0.0",
"node-fetch": "^2.6.0",
"nodemon": "^2.0.2"
},
"devDependencies": {
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"eslint": "^4.19.1",
"mocha": "^5.2.0",
"nyc": "^12.0.2",
"sinon": "^6.0.0",
"sinon-chai": "^3.2.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
Contract.js snippet:
/**
*
* #param {*} ctx
* #param {*} partialKey - Piece of key to serch
*/
async getAllStates(ctx, partialKey) {
let result = await ctx.informedConsentFormStateList.getStatesFromPartialCompositeKey(partialKey);
console.log('================ Result inside getAllStates method ================');
console.log(result);
return result;
} // fin func
Insinde informedConsentFormStateList.js:
```
async getStatesFromPartialCompositeKey(partialKey) {
return this.getAllStatesFromPartialCompositeKey(partialKey);
}
```
Inside the modified stateList.js:
/**
* #function getAllStatesFromPartialCompositeKey
*/
async getAllStatesFromPartialCompositeKey(partialArgument) {
console.log('================ Called from beginning of getAllStatesFromPartialCompositeKey ================');
console.log('================ name => ' + this.name);
let key = this.ctx.stub.createCompositeKey(this.name, [partialArgument]);
console.log('================ created partial key .....');
console.log(partialArgument);
console.log(key);
let response = await this.ctx.stub.getStateByPartialCompositeKey(this.name, [key]); //.toString('utf8')
console.log('================ response below ================');
console.log(response);
let results = await this.getAllResults(response);
return results;
} // fin getAllStatesFromPartialCompositeKey
Here is how I invoke it:
/home/ubilab/fabric2/fabric-samples/test-network$ peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name informed_consent_9 --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA -c '{"Args":["csacmpcc:getAllStates","P03"]}'
Response:
chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"[]"
Chaincode container logs:
================ Called from beginning of getAllStatesFromPartialCompositeKey ================
================ name => org.csa.informedconsentformstatelist
================ created partial key .....
P03
org.csa.informedconsentformstatelistP03
================ Result inside getAllStates method ================
[]
Couchdb Stored state:
{
"id": "\u0000org.csa.informedconsentformstatelist\u0000\"P03\"\u0000\"R68\"\u0000",
"key": "\u0000org.csa.informedconsentformstatelist\u0000\"P03\"\u0000\"R68\"\u0000",
"value": {
"rev": "1-74db76a10ad8251ce2ba49ad58710ad8"
},
"doc": {
"_id": "\u0000org.csa.informedconsentformstatelist\u0000\"P03\"\u0000\"R68\"\u0000",
"_rev": "1-74db76a10ad8251ce2ba49ad58710ad8",
"class": "org.csa.informedconsentform",
"consentStatus": "1",
"currentState": null,
"key": "\"P03\":\"R68\"",
"patientID": "P03",
"reserachID": "R68",
"sensors": "{numberOfSensors:1,sensors:[{sensorID:s01,name:SPO2,startDate:5/12/2020,endDate:5/12/2021}]}",
"~version": "CgMBZQA="
}
}
If you need more information to be able to help me please do not hesitate to ask :). Thanks!
Given you are querying with a single attribute, try using the partialKey variable directly instead of building a composite key.
let response = await this.ctx.stub.getStateByPartialCompositeKey(this.name, [partialKey]);
API docs
A better way to get a response would be to use an iterator :
let allResults = [];
let res = { done: false, value: null };
let jsonRes = {};
res= await ctx.stub.getStateByPartialCompositeKey(this.name, [partialKey]);
while (!res.done) {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
allResults.push(jsonRes);
res = await iterator.next();
}
catch (err) {
console.log(err);
return {}
}
}
await iterator.close();
return allResults;

jest-fetch-mock: mocks only work if they are declared in components

I'm trying to test a React app with Rails backend. I'm trying to write tests in jest.
I'm using jest-fetch-mock node module to mock API calls. For some reason, it doesn't work properly.
This works, but fails in tests
//PhoneCodeList.jsx
class PhoneCodeList extends React.Component {
async componentDidMount() {
try {
const response = await fetch(`/api/v1/phone-codes`);
const response_json = await response.json()
// do stuff
console.log(response_json)
}
catch(e) {
console.log(e)
}
}
}
// PhoneCodeList.test.js
import React from 'react'
import {mount, shallow, render, configure} from 'enzyme'
import PhoneCodeList from 'components/PhoneCodeList.js'
import Adapter from 'enzyme-adapter-react-16';
global.fetch = require('jest-fetch-mock')
configure({ adapter: new Adapter() })
const wrapper = mount(<PhoneCodeList />);
describe('Phone list', function() {
test('Lists at least one phone code from database', async () => {
fetch.mockResponse(JSON.stringify({ data: [{id: 1, attributes: { prefix: 'foo'}},
{id: 2, attributes: { prefix: 'bar'}}]}))
var resp = render(<PhoneCodeList />);
expect(resp.find('.phone-code-row').length).toBeGreaterThan(0);
})
})
Response:
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: { body: '', disturbed: false, error: null },
[Symbol(Response internals)]:
{ url: undefined,
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object: null prototype] {} } } }
But mock suddenly starts working if I place it in react file
//PhoneCodeList.jsx
class PhoneCodeList extends React.Component {
async componentDidMount() {
try {
fetch.mockResponse(JSON.stringify({ data: [{id: 1, attributes: { prefix: 'foo'}},
{id: 2, attributes: { prefix: 'bar'}}]}))
const response = await fetch(`/api/v1/phone-codes`);
const response_json = await response.json()
// do stuff
console.log(response_json)
}
catch(e) {
console.log(e)
}
}
}
Obviously, I don't want to leave mocks in my actual React files. What causes them to fail and how to prevent it?
update 01
Config files:
// setupJest.js
global.fetch = require('jest-fetch-mock')
// package.json
{
"name": "germany_phone_codes",
"private": true,
"dependencies": {
"#babel/preset-react": "^7.6.3",
"#rails/webpacker": "^4.0.7",
"#reach/router": "^1.2.1",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
"jest-enzyme": "^7.1.2",
"prop-types": "^15.7.2",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react_ujs": "^2.6.0",
"yarn": "^1.19.1"
},
"devDependencies": {
"babel-jest": "^24.9.0",
"jest": "^24.9.0",
"jest-fetch-mock": "^2.1.2",
"react-test-renderer": "^16.12.0",
"regenerator-runtime": "^0.13.3",
"webpack-dev-server": "^3.9.0"
},
"scripts": {
"test": "jest",
"test-watch": "jest --watch"
},
"jest": {
"roots": [
"test/javascript"
],
"moduleDirectories": [
"node_modules",
"app/javascript"
],
"automock": false,
"setupFiles": [
"./setupJest.js"
]
}
}

Categories