Shopify App Node.js template: Testing Errors - jestjs

Overview
I have been having A LOT of problems running basic unit tests with shopify's node app setup: https://github.com/Shopify/shopify-app-template-node
When trying to use the #shopify/react-testing library, with Jest as the runner, I keep getting this TypeError of testUtils.act is not a function.
TextFieldComponent.test.tsx
import { mount } from '#shopify/react-testing';
import TextFieldComponent from "../../components/atoms/TextFieldComponent";
describe("TextFieldComponent", () => {
it("renders TextFieldComponent", () => {
const testId = "text-field";
const value = "test";
const label = "test";
const type = "text";
const autoComplete = "off";
const wrapper = mount( <TextFieldComponent
value={value}
type={type}
autoComplete={autoComplete}
label={label}
/>);
});
});
jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom'
}
The Error:
testUtils.act is not a function

Related

How to override url for RTK query

I'm writing pact integration tests which require to perform actual call to specific mock server during running tests.
I found that I cannot find a way to change RTK query baseUrl after initialisation of api.
it('works with rtk', async () => {
// ... setup pact expectations
const reducer = {
[rtkApi.reducerPath]: rtkApi.reducer,
};
// proxy call to configureStore()
const { store } = setupStoreAndPersistor({
enableLog: true,
rootReducer: reducer,
isProduction: false,
});
// eslint-disable-next-line #typescript-eslint/no-explicit-any
const dispatch = store.dispatch as any;
dispatch(rtkApi.endpoints.GetModules.initiate();
// sleep for 1 second
await new Promise((resolve) => setTimeout(resolve, 1000));
const data = store.getState().api;
expect(data.queries['GetModules(undefined)']).toEqual({modules: []});
});
Base api
import { createApi } from '#reduxjs/toolkit/query/react';
import { graphqlRequestBaseQuery } from '#rtk-query/graphql-request-base-query';
import { GraphQLClient } from 'graphql-request';
export const client = new GraphQLClient('http://localhost:12355/graphql');
export const api = createApi({
baseQuery: graphqlRequestBaseQuery({ client }),
endpoints: () => ({}),
});
query is very basic
query GetModules {
modules {
name
}
}
I tried digging into customizing baseQuery but were not able to get it working.

How to mock #google-cloud/kms using jest

I'm trying to write unit test cases for decrypt. I've my own implementation of decrypting an encrypted file. While trying to import the decrypt.mjs facing the following error.
Must use import to load ES Module: /node_modules/bignumber.js/bignumber.mjs
My application is a react frontend and NodeJS backend. I've used ES6 modules for NodeJS. Here is my decrypt.mjs file
import { readFile } from 'fs/promises';
import path from 'path';
import { KeyManagementServiceClient } from '#google-cloud/kms';
const decrypt = async (APP_MODE, __dirname) => {
if (APP_MODE === 'LOCALHOST') {
const keys = await readFile(
new URL(`./stagingfile.json`, import.meta.url)
).then((data) => JSON.parse(data));
return keys;
}
const { projectId, locationId, keyRingId, cryptoKeyId, fileName } =
getKMSDefaults(APP_MODE);
const ciphertext = await readFile(
path.join(__dirname, `/${fileName}`)
);
const formattedName = client.cryptoKeyPath(
projectId,
locationId,
keyRingId,
cryptoKeyId
);
const request = {
name: formattedName,
ciphertext,
};
const client = new KeyManagementServiceClient();
const [result] = await client.decrypt(request);
return JSON.parse(result.plaintext.toString('utf8'));
};
const getKMSDefaults = (APP_MODE) => {
//Based on APP_MODE the following object contains different values
return {
projectId: PROJECT_ID,
locationId: LOCATION_ID,
keyRingId: KEY_RING_ID,
cryptoKeyId: CRYPTO_KEY_ID,
fileName: FILE_NAME,
};
};
export default decrypt;
I tried to mock the #google-cloud/kms using manual mock (jest) but it didn't work. I tried multiple solutions to mock but nothing worked and it ended with the Must use import to load ES Module error.
I've had successfully used jest to mock #google-cloud/kms with TypeScript, so hopefully this will be the same process for ES modules that you can use.
Example working code:
// jest will "hoist" jest.mock to top of the file on its own anyway
jest.mock("#google-cloud/kms", () => {
return {
KeyManagementServiceClient: jest.fn().mockImplementation(() => {
return {
encrypt: kmsEncryptMock,
decrypt: kmsDecryptMock,
cryptoKeyPath: () => kmsKeyPath,
};
}),
};
});
// give names to mocked functions for easier access in tests
const kmsEncryptMock = jest.fn();
const kmsDecryptMock = jest.fn();
const kmsKeyPath = `project/location/keyring/keyname`;
// import of SUT must be after the variables used in jest.mock() are defined, not before.
import { encrypt } from "../../src/crypto/google-kms";
describe("Google KMS encryption service wrapper", () => {
const plaintext = "some text to encrypt";
const plaintextCrc32 = 1897295827;
it("sends the correct request to kms service and raise error on empty response", async () => {
// encrypt function is async that throws a "new Error(...)"
await expect(encrypt(plaintext)).rejects.toMatchObject({
message: "Encrypt: no response from KMS",
});
expect(kmsEncryptMock).toHaveBeenNthCalledWith(1, {
name: kmsKeyPath,
plaintext: Buffer.from(plaintext),
plaintextCrc32c: { value: plaintextCrc32 },
});
});
});

nodejs get error 'originalType.toConfig is not a function'

I am trying to make a test run of an application using graphql. But I get the error
types resolvers
src/api/Hello/sayBye/sayBye.graphql
type Query {
sayBye: String!
}
src/api/Hello/sayBye/sayBye.resolvers.ts
const resolvers = {
Query: {
sayBye: () => "Hello from sayBye"
}
}
export default resolvers;
src/api/Hello/sayHello/sayHello.graphql
type Query {
sayHello: String!
}
src/api/Hello/sayHello/sayHello.resolvers.ts
const resolvers = {
Query: {
sayHello: () => "Hello from sayHello"
}
}
export default resolvers;
merge types and resolvers
src/schema.ts
import { GraphQLSchema } from "graphql";
import { makeExecutableSchema } from '#graphql-tools/schema';
import { fileLoader, mergeTypes, mergeResolvers } from "merge-graphql-schemas";
import * as path from "path";
const allTypes: GraphQLSchema[] = fileLoader(
path.join(__dirname, "./api/**/*.graphql")
);
const allResolvers = fileLoader(
path.join(__dirname, "./api/**/*.resolvers.*")
);
const mergedTypes = mergeTypes(allTypes);
const mergedResolvers = mergeResolvers(allResolvers);
const schema = makeExecutableSchema({
typeDefs: mergedTypes,
resolvers: mergedResolvers
});
export default schema;
error
[nodemon] starting ts-node index.ts
/var/www/html/dist/utils/src/mapSchema.js:205
Object.keys(originalTypeMap).forEach(typeName => { ^ TypeError:
originalType.toConfig is not a function at
/var/www/html/dist/utils/src/mapSchema.js:217:41 at Array.forEach
() at mapArguments
(/var/www/html/dist/utils/src/mapSchema.js:205:34) at mapDefaultValues
(/var/www/html/dist/utils/src/mapSchema.js:97:24) at Object.mapSchema
(/var/www/html/dist/utils/src/mapSchema.js:7:22) at
createNewSchemaWithResolvers
(/var/www/html/dist/schema/src/addResolversToSchema.js:200:14) at
addResolversToSchema
(/var/www/html/dist/schema/src/addResolversToSchema.js:87:11) at
schemaTransforms
(/var/www/html/dist/schema/src/makeExecutableSchema.js:66:41) at
/var/www/html/dist/schema/src/makeExecutableSchema.js:108:65 at
Array.reduce () [nodemon] app crashed - waiting for file
changes before starting...

Using a variable hangs build process when accessed via import

GitHub discussion w/ solution: https://github.com/prisma/prisma/discussions/4038#discussioncomment-111664
I'm building a full-stack app and I'm using Prisma and Web3. As part of Prisma's build process I use yarn generate to compile the schema. I've run into some strange issue where my program is hanging on a return statement.
// ./modules/Wallet.ts
import Web3 from 'web3'
// create a Web3 connection
export const web3 = new Web3(
process.env.NODE_ENV === 'production'
? 'wss://mainnet.infura.io/ws/v3/redacted'
: 'wss://ropsten.infura.io/ws/v3/redacted'
)
// load an Ethereum wallet from a private key (env var)
const envWallet = () => {
if (!process.env.ETH_PRIVATE_KEY) {
require('dotenv').config()
}
const _wallet = web3.eth.accounts.wallet.add(process.env.ETH_PRIVATE_KEY!)
// successfully logs the loaded wallet on `yarn generate`
console.log(_wallet)
// Issue: `yarn generate` hangs on this line
return _wallet
}
// initialize the wallet
const wallet = envWallet()
// get the address of the wallet
export const getAddress = () => {
return wallet.address
}
// ./types/Query.ts
// If I omit this file from the schema, it will compile successfully
import { queryType } from '#nexus/schema'
import { getAddress } from '../modules/Wallet'
console.log('Test 1') // logged after the console.log(_wallet)
const Query = queryType({
definition(t) {
// simply a GraphQL query that returns the address of the loaded wallet
t.string('getAddress', {
nullable: true,
resolve: (root, args, ctx) => {
console.log('Test 2') // never hits
const address = getAddress()
console.log('Test 3') // never hits
return address
},
})
},
})
export default Query

Jest mocking module

I am writing unit tests for a node application using Jest.
The Node code is using a third party library to log information.
The library has a function getLogger which you should call to return a logger object.
I am trying to mock the calls for that library and detect its calls in my unit test.
The node code is as follows:
const logger = require('third-party-libary').getLogger('myModule')
....
function submitSomething() {
....
logger.info('log something')
}
In my Jest unit test, I tried to mock those logger calls in many different ways, with no success, and always come back as "logger is not defined"
I tried:
jest.mock('third-party-library');
const loggerFactory = require('third-party-library');
const logger = {
error: jest.fn(),
info: jest.fn()
};
loggerFactory.getLogger.mockImplementation(() => logger);
But it always return error :
cannot find "info" for null object
I tried this as well:
jest.mock('third-party-library')
const loggerFactory = require('third-party-library');
const logger = {
error: jest.fn(),
info: jest.fn()
};
loggerFactory.getLogger = () => logger
I tried this:
jest.mock('third-party-library')
const loggerFactory = require('third-party-library');
const logger = {
error: jest.fn(),
info: jest.fn()
};
loggerFactory.getLogger = jest.fn(() => logger)
With the same error
I switched between the jest.mock to make it after the require, with no luck
Your approach works fine, just note that your code creates logger as soon as it runs so the mock for getLogger has to be in place before the code is required:
jest.mock('third-party-library');
const loggerFactory = require('third-party-library');
const logger = {
error: jest.fn(),
info: jest.fn()
};
// const { submitSomething } = require('./code'); <= would NOT work here
loggerFactory.getLogger.mockReturnValue(logger);
const { submitSomething } = require('./code'); // <= works here
test('submitSomething', () => {
submitSomething();
expect(logger.info).toHaveBeenCalledWith('log something'); // Success!
});

Resources