React Intl `undefined()` must be called with an object expression - react-intl

React intl doesn't build on CI with following error:
[React Intl] undefined() must be called with an object expression with values that are React Intl Message Descriptors, also defined as object expressions.
Tried this:
Issue link
But it doesn't help.
import ConnectedComponent from './ConnectedComponent';
import {connect} from 'react-redux';
import {injectIntl, defineMessages} from 'react-intl';
const messages = defineMessages({
LABEL: {id: "CONNECTED.COMPONENT.LABEL", defaultMessage: "Label"},
});
const mapStateToProps = (state, ownProps) => {
const { intl } = ownProps;
return {
inputLabel: intl.formatMessage(messages.LABEL),
};
};
export default injectIntl(connect(
mapStateToProps
)(ConnectedComponent));

Looks like it's a bug in babel-plugin-react-intl [1], which is supposedly fixed already.
[1] https://github.com/formatjs/formatjs/issues/37

Related

Trouble Writing to Jest Mocked Prisma Database

I have two databases that I need to interact with in my code. I have a simple function that takes an object and writes it to my PostgreSQL database using Prisma. I've tested the function with Postman, and it works perfectly, but when I try to execute it using a Jest mock (using the singleton pattern found in the Prisma unit testing guide), it returns undefined indicating that it didn't interact with the database and create the new record. Here's my code:
/prisma/clinical-schema.prisma
generator client {
provider = "prisma-client-js"
output = "./generated/clinical"
}
datasource clinicalDatabase {
provider = "postgresql"
url = "postgresql://postgres:postgres#localhost:5432/clinical-data?schema=public"
}
model pcc_webhook_update {
id Int #id #default(autoincrement())
event_type String
organization_id Int
facility_id Int
patient_id Int
resource_id String?
webhook_date DateTime #default(now()) #clinicalDatabase.Timestamptz(6)
status pcc_webhook_update_status #default(pending)
status_changed_date DateTime? #clinicalDatabase.Timestamptz(6)
error_count Int #default(0)
##unique([organization_id, facility_id, patient_id, resource_id, event_type, status])
}
enum pcc_webhook_update_status {
pending
processing
processed
error
}
/prisma/clinical-client.ts
import { PrismaClient } from './generated/clinical';
const prismaClinical = new PrismaClient();
export default prismaClinical;
/testing/prisma-clinical-mock.ts
import { PrismaClient } from '../prisma/generated/clinical';
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended';
import prisma from '../prisma/clinical-client';
jest.mock('../prisma/clinical-client', () => ({
__esModule: true,
default: mockDeep<PrismaClient>()
}));
beforeEach(() => {
mockReset(prismaClinicalMock);
});
export const prismaClinicalMock = prisma as unknown as DeepMockProxy<PrismaClient>;
Everything up to this point follows the conventions outlined by the Prisma unit testing docs. The only modification I made was to make it database specific. Below is my function and tests. The request object in handle-pcc-webhooks.ts is a sample http request object, the body of which contains the webhook data I care about.
/functions/handle-pcc-webhooks/handler.ts
import prismaClinical from '../../../prisma/clinical-client';
import { pcc_webhook_update } from '../../../prisma/generated/clinical';
import { requestObject } from './handler.types';
export const handlePccWebhook = async (request: requestObject) => {
try {
const webhook = JSON.parse(request.body);
// if the webhook doesn't include a resource id array, set it to an array with an empty string to ensure processing and avoid violating
// the multi-column unique constraint on the table
const { resourceId: resourceIds = [''] } = webhook;
let records = [];
for (const resourceId of resourceIds) {
// update an existing record if one exists in the pending state, otherwise create a new entry
const record: pcc_webhook_update = await prismaClinical.pcc_webhook_update.upsert({
where: {
organization_id_facility_id_patient_id_resource_id_event_type_status: {
organization_id: webhook.orgId,
facility_id: webhook.facId,
patient_id: webhook.patientId,
resource_id: resourceId,
event_type: webhook.eventType,
status: 'pending'
}
},
update: {
webhook_date: new Date()
},
create: {
event_type: webhook.eventType,
organization_id: webhook.orgId,
facility_id: webhook.facId,
patient_id: webhook.patientId,
resource_id: resourceId,
status: 'pending' // not needed
}
});
records.push(record);
}
return records;
} catch (error) {
console.error(error);
}
};
/functions/handle-pcc-webhooks/handler.spec.ts
import fs from 'fs';
import path from 'path';
import MockDate from 'mockdate';
import { prismaClinicalMock } from '../../../testing/prisma-clinical-mock';
import { createAllergyAddRecord } from './__mocks__/allergy';
import { requestObject } from './handler.types';
import { handlePccWebhook } from './handler';
describe('allergy.add', () => {
let requestObject: requestObject;
let allergyAddRecord: any;
beforeAll(() => {
requestObject = getRequestObject('allergy.add');
});
beforeEach(() => {
MockDate.set(new Date('1/1/2022'));
allergyAddRecord = createAllergyAddRecord(new Date());
});
afterEach(() => {
MockDate.reset();
});
test('should create an allergy.add database entry', async() => {
prismaClinicalMock.pcc_webhook_update.create.mockResolvedValue(allergyAddRecord);
// this is where I would expect handlePccWebhook to return the newly created database
// record, but instead it returns undefined. If I run the function outside of this
// unit test, with the same input value, it functions perfectly
await expect(handlePccWebhook(requestObject)).resolves.toEqual([allergyAddRecord]);
});
});
// This just builds a request object with the current webhook being tested
function getRequestObject(webhookType: string) {
// read the contents of request object file as a buffer, then convert it to JSON
const rawRequestObject = fs.readFileSync(path.resolve(__dirname, '../../sample-data/handle-pcc-webhook-request.json'));
const requestObject: requestObject = JSON.parse(rawRequestObject.toString());
// read the contents of the webhook file as a buffer, then convert it to a string
const rawWebhook = fs.readFileSync(path.resolve(__dirname, `../../sample-data/${webhookType}.json`));
const webhookString = rawWebhook.toString();
// set the body of the request object to the contents of the target webhook
requestObject.body = webhookString;
return requestObject;
}
Finally, here is the result of running the unit test:
So after banging my had against the wall for a few hours, I figured out the issue. In my handler.spec.ts file, I had the following line:
prismaClinicalMock.pcc_webhook_update.create.mockResolvedValue(allergyAddRecord);
what that does is mock the value returned for any create functions run using Prisma. The issue is that my function is using an upsert function, which I wasn't explicitly mocking, thus returning undefined. I changed the above line to
prismaClinicalMock.pcc_webhook_update.upsert.mockResolvedValue(allergyAddRecord);
and it started working.

How to use CodeceptJS to unit-test a JS function

I've set up CodeceptJS for a project and use it to test various end-to-end scenarios.
Now I want to extend the tests-suite to also run unit-tests to verify functionality of custom JS functions.
For example: I have a global object App that has a version attribute. As a first test, I want to confirm that App.version is present and has a value.
My first attempt is a test.js file with the following code:
Feature('Unit Tests');
Scenario('Test App presence', ({ I }) => {
I.amOnPage('/');
I.executeScript(function() {return App.version})
.then(function(value) { I.say(value) } );
});
Problems with this code
The major issue: How can I assert that the App.version is present?
My script can display the value but does not fail if it's missing
My code is very complex for such a simple test.
I'm sure there's a cleaner/faster way to perform that test, right?
Here is a solution that works for me:
Read data from the browser:
I created a custom helper via npx codecept gh and named it BrowserAccess.
The helper function getBrowserData uses this.helpers['Puppeteer'].page.evaluate() to run and return custom code from the browser scope. Documentation for .evaluate()
Custom assertions:
Install the codeceptjs-assert package, e.g. npm i codeceptjs-assert
Add the AssertWrapper-helper to the codecept-config file. This enables checks like I.assert(a, b)
Full Code
codecept.conf.js
exports.config = {
helpers: {
AssertWrapper: {
require: "codeceptjs-assert"
},
BrowserAccess: {
require: './browseraccess_helper.js'
},
...
},
...
}
browseraccess_helper.js
const Helper = require('#codeceptjs/helper');
class BrowserAccess extends Helper {
async getBrowserData(symbolName) {
const currentPage = this.helpers['Puppeteer'].page;
let res;
try {
res = await currentPage.evaluate((evalVar) => {
let res;
try {
res = eval(evalVar);
} catch (e) {
}
return Promise.resolve(res);
}, symbolName);
} catch (err) {
res = null;
}
return res;
}
}
jsapp_test.js (the test is now async)
Feature('Unit Tests');
Scenario('Test App presence', async ({ I }) => {
I.amOnPage('/');
const version = await I.getBrowserData('App.version');
I.assertOk(version);
});

Unable to add objects into Redux state during unit test

I'm attempting to add objects into my Redux store during a unit test to ensure my reducers and actions are working properly. It looks like the state that is showing up is the INITIAL_STATE from the reducer file. However, any time I add a new item into the reducer state, nothing happens. I'm presuming it's because it's adding too slow and it's async. Not really sure how to approach this.
Reducer/Action Test
/***********************
TESTING THE REDUX STORE
***********************/
describe('>>>Redux Store for Budget Functionality', () => {
beforeEach(() => {
store = configureStore();
})
it('Should successfully add a new budget into the store', () => {
let budgetCategory = testHelper.testBudgetCategory;
//Will auto dispatch since we are using redux-actions
const action = addBudgetCategoryRequest(budgetCategory);
const actual = store.getState().getIn(['budget', 'budgetCategories']).toJS()
const expected = [testHelper.testBudgetCategory];
expect(actual).toEqual(expected);
})
Store File
import {createStore, applyMiddleware, compose} from 'redux';
import thunk from 'redux-thunk';
import reducers from './reducers';
export function configureStore(){
// Use redux dev tools if available, otherwise use default composition;
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers, composeEnhancers(
applyMiddleware(thunk)
));
return store;
}
My entire reducer/action create file
import Immutable from 'immutable'
import { createAction } from 'redux-actions';
import axios from 'axios';
import moment from 'moment';
/**************
INITIAL STATE
***************/
export const INITIAL_STATE = Immutable.fromJS({
budgetCategories: [],
budgetFormEditable: {errors: [{budgetNameError: false, monthlyCostError: false}] },
});
/**************
TYPES
***************/
export const ADD_BUDGET = 'src/Budget/ADD_BUDGET';
export const ADD_EDITABLE_FIELD_ERRORS = 'src/Budget/ADD_EDITABLE_FIELD_ERRORS';
export const UPDATE_BUDGET_ENTRY = 'src/Budget/UPDATE_BUDGET_ENTRY';
/**************
REDUCER LOGIC FLOW
***************/
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_BUDGET:
return state.updateIn(['budgetCategories'], arr => arr.push(Immutable.fromJS(action.payload)))
case ADD_EDITABLE_FIELD_ERRORS:
return state.setIn(['budgetFormEditable', 'errors', 0], Immutable.fromJS(action.payload))
case UPDATE_BUDGET_ENTRY:
console.log("The field that we are editing is " + action.payload.editedStateIndex);
return state.setIn(
[
'budgetCategories',
action.payload.editedStateIndex,
], Immutable.fromJS(action.payload.newBudget));
default:
return state;
}
}
/**************
ACTIONS CREATORS
***************/
export const addBudget = createAction(ADD_BUDGET);
export const addEditableFieldErrors = createAction(ADD_EDITABLE_FIELD_ERRORS);
export const updateBudgetEntry = createAction(UPDATE_BUDGET_ENTRY);
/**************
ACTION REQUESTS
***************/
//TODO: Honestly, this is pretty unnecessary as I am not resolving promises
export function addBudgetCategoryRequest(data) {
return (dispatch) => {
dispatch(addBudget(data));
}
}

mocking a require()'d imported object with jest/sinon

here's my code:
const Config = require('Config');
export const getPayments = (username: string) => {
if (username === undefined) {
throw new Error('username is undefined');
}
const envEndpoint = Config.paymentsEndpoint;
const endpoint: string = `${envEndpoint}/${username}`;
return fetch(endpoint);
};
What I want to mock is the Config object. I basically want to intercept that require call in my test file and replace it with a an object with that paymentsEndpoint value. I am using jest, but also have sinon as an option for mocking.
I am still fairly new to unit tests and jest, so forgive me if I used incorrect terminology
In your test file before you import your getPayments module, you can use jest.mock to mock the Config module.
So it would look something like
/* getPayments.test.js */
jest.mock('Config', () => {
return { paymentsEndpoint: 'y' }; // return your fake Config obj here
});
import getPayments from './getPayments'; // or whatever the correct file path is
describe(() => {
[ ... your tests ]
});
here are the jest.mock docs: https://facebook.github.io/jest/docs/en/jest-object.html#jestmockmodulename-factory-options

ionic media plugin - pass onStatusUpdate to mediaObject?

I'm trying to use ionic native's media plugin like this:
record(){
...
return this.media.create(src,onStatusUpdate).then((mediaObj) => {
mediaObj.startRecord();
return mediaObj;
});
}
And I use the mediaObj returned from it elsewhere, but I also need to know the status of the mediaObj; this apparently comes from passing a second argument, a callback function, to the media.create() function. However, I don't know how to get the mediaObj's status in there. I know the following would work for just telling me the status, but I actually need to access it.
const onStatusUpdate = (status) => console.log(status);
So, the question is, is there a way to simply access the mediaObj's status?
The MediaPlugin status update notification is all you get so set a class property with the value you get when the status change.
To manage the MediaObject I set a property to the value obtained when the promise is resolved.
import { ApplicationRef } from '#angular/core';
...
...
export class PlayerPage {
track:any;
file:MediaObject = undefined;
position:any = undefined;
status:any = 0;
constructor(public ref ApplicationRef, public navCtrl: NavController, private navParams: NavParams, public AppstateProvider: Appstate, private media: MediaPlugin) {
this.track = navParams.get('track');
media.create('http://.../...mp3',(status)=>{
this.status = status;
this.ref.tick();
}).then((file: MediaObject) => {
this.file = file;
});
}
play() {
this.file.play();
}
The this.ref.tick(); is necesarry because Angular does not detect this property update - I tried publishing and subscribing Angular still did not detect the property update.