Jest error with <Trans>: You forgot to export your component from the file it's defined in, or you might have mixed up default and named imports - jestjs

Error: Uncaught [Error: Element type is invalid: expected a string
(for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in, or you might have mixed up
default and named imports.
This is the error I was getting while running test in jest. React component which is being tested uses <Trans> from react-i18next. When I comment that portion of code, test were working as expected.

The error shown is very very very miss leading.
In my case it was missing mock for <Trans>. While I had mock for react-i18next, but since I had many components to cover with tests, and some of them were using <Trans> and some of them not, I copy/paste test files but totally forgot to check about mock. It took me few hours to notice it, after I replaced <Trans> to text like <Typography> from material-ui...
jest.mock('react-i18next', () => ({
withTranslation: () => (Component: any) => {
Component.defaultProps = {...Component.defaultProps, t: (children: any) => children};
return Component;
},
Trans: ({children}: any) => children, // this line was missing (() => jest.fn() might also work)
}));
Hope it will save some time for some of you :)

I faced the same issue, in order to resolve the issue I mocked the Trans component like this
jest.mock("react-i18next", () => ({
Trans: ({ i18nKey }: { i18nKey: string }) => i18nKey,
}));
Instead of passing the node, we can simply pass the i18nKey.
In my case, I am only checking the key value. Hope it helps!

Related

Property 'updateEnabledSubmitSignup' does not exist on type 'typeof SvelteComponentDev' when trying to use an exported Svelte component function

I want to export a function from a Svelte component and import it into a Jest test file for testing.
My expected result based on this post is that I can do:
// index.svelte
<script>
export function updateEnabledSubmitSignup(email, username, password, confirmedPassword) {
// ...
}
</script>
and then in my test file:
import Signup from "../src/routes/signup/index.svelte"
describe("signup page logic", () => {
test("ensure that the signup form button enablement conditions work properly", () => {
console.log(Signup, "5rm")
const failureOne = Signup.updateEnabledSubmitSignup()
expect(failureOne).toBe(false)
})
})
But running this code gives
tests/signup.test.ts:6:31 - error TS2339: Property 'updateEnabledSubmitSignup' does not exist on type 'typeof SvelteComponentDev'.
6 const failureOne = Signup.updateEnabledSubmitSignup()
It fails also if I do <script context="module"> with Property 'updateEnabledSubmitSignup' does not exist on type 'typeof SvelteComponentDev'.
If I try a named import like
import { updateEnabledSubmitSignup } from "../src/routes/signup/index.svelte"
then running the test gives error TS2614: Module '"*.svelte"' has no exported member 'updateEnabledSubmitSignup'. Did you mean to use 'import updateEnabledSubmitSignup from "*.svelte"' instead?
Anyone know how to do this please? This reddit post claims "You can use the tag at the top of your component to export a function." But even though I do that, the import fails.
Functions exported from the regular script are on the instance, e.g.
let signup;
onMount(() => signup.updateEnabledSubmitSignup());
<Signup bind:this={signup} />
Functions exported from the context=module script are named exports of the file.
If you get a type error from that, it is because your tooling did not determine the types correctly (it generically says *.svelte instead of the concrete type of this specific component). Question being, why your tests are doing type checking in the first place.

Wrap a problematic npm package, while maintaining type information

The Problem
We're authoring an npm package containing React components that will be used in various (internal) web sites. There is a problematic npm package dependency that we are forced to use in our react .tsx files, that has these problems:
It doesn't expose any useful types despite having .d.ts files in it... they're empty.
It tries to run when required or imported server-side, instead of waiting until called, so we have to avoid a top-level import and instead do if (window) { const module = require('package-name') } and then use it inside that block only.
It is a frequent source of errors so everything in that library needs to be run inside of a try ... catch block.
Well, At Least We Have Types
We have already created our own types file which addressed problem #1:
// problematic-package-types.d.ts
declare module 'problematic-package' {
function doErrorProneButNecessaryThing(
foo: Record<string, unknown>,
bar: string
): void
}
The Needed Solution
The long term solution is to fix this problematic library and we're looking into how to get that done (but it's not in our direct control).
In the short term, though, we need a solution now.
Note that we are configuring dynamic requires in our npm package bundler to import them only at use-time, not treating them like other imports/requires. As our package is consumed inside other applications, we don't have full control over how that application bundling works or when the components are required, so our components may end up being required server-side when they shouldn't, and we have to tolerate that. We're still learning about some aspects of this.
My Wild (But Failed) Stab
My goal is to do something more DRY like this, where we solve all three problems of strong typing, detecting server-side execution & doing nothing, and adding error handling:
// hoping to leverage our module declaration above without importing anything
import type * as ProblematicPackage from 'problematic-package'
import wrapProblematicRequire from '../utils/my-sanity-preserving-module'
const wrappedProblematicPackage = wrapProblematicRequire<ProblematicPackage>()
// then later...
const foo: Record<string, unknown> = { property1: 'yes', property2: false }
const bar = 'yodeling'
wrappedProblematicPackage.invokeIfWindowReady(
'doErrorProneButNecessaryThing',
foo,
bar
)
However, TypeScript doesn't like the import type which unfortunately makes sense:
Cannot use namespace 'ProblematicPackage' as a type.
The Plea
How do I get the type information we've placed into problematic-package-types.d.ts to use as desired?
Or ANYTHING else. Honestly, I'm open to whatever, no matter how crude or hacky, so long as we get some clarity and reliability at call sites, with full type information as described. Suggestions/advice?
Full Details
Here is the full implementation of the wrapProblematicRequire function. I haven't tested it. It's probably awful. I'm sure it could be far better but I don't have time to get this helper module super clean right now. (My attempt to handle function type information isn't quite right.)
type Func = (...args: any[]) => any
type FunctionNames<T, TName extends keyof T> = T[TName] extends Func ? TName : never
type FunctionNamesOf<T> = FunctionNames<T, keyof T>
const wrapProblematicRequire = <T>(packageName: string) => ({
invokeIfWindowReady<TName extends FunctionNamesOf<T>>(
name: T[TName] extends Func ? TName : never,
...args: T[TName] extends Func ? Parameters<T[TName]> : never
): T[TName] extends Func ? ReturnType<T[TName]> : never {
if (!window) {
// #ts-ignore
return undefined
}
try {
// #ts-ignore
return require(packageName)[name] as T[TName](...args)
} catch (error: unknown) {
// ToDo: Log errors
// #ts-ignore
return undefined
}
}
})
export default wrapProblematicRequire
P.S. await import('problematic-package') didn't seem to work. Yes, problems abound.
Cannot use namespace 'ProblematicPackage' as a type.
Well, you can get the typeof that namespace, which seems to be what you want.
To test this, I setup the following:
// problem.js
export function doErrorProneButNecessaryThing(n) {
return n;
}
export function doErrorProneButNecessaryThing2(s) {
return s;
}
console.log('did side effect');
// problem.d.ts
export function doErrorProneButNecessaryThing(n: number): number;
export function doErrorProneButNecessaryThing2(s: string): string;
And now you can do:
import type * as ProblemNs from './problem';
type Problem = typeof ProblemNs;
// works
type A = Problem['doErrorProneButNecessaryThing'] // type A = (n: number) => number
Then the wrapProblematicRequire function just takes the name of the function as a generic, pulls the args for it, and pulls the return type.
const wrapProblematicRequire = <TName extends FunctionNamesOf<Problem>>(
name: TName,
...args: Parameters<Problem[TName]>
): ReturnType<Problem[TName]> | undefined => {
if (!window) return;
const problem = require('./problem'); // type is any, but types are enforced above
try {
return problem[name](...args);
} catch (err) {
console.log('error!');
}
};
Here require('./problem') returns the any type, but the generics keep everything key safe as long as typeof ProblemNs can be trusted.
Now to test that:
console.log('start');
const result: number = wrapProblematicRequire(
'doErrorProneButNecessaryThing',
123
);
console.log('end');
Which logs:
start
did side effect
end
Which seems to work!
Codesandbox

Apply node module with object prototype methods

Good morning.
I'm trying to create a node module witch right now is published as redgem.
It consists of adding methods to base objects prototypes. For example:
const obj = { a: 'b', c: 'd' }
obj.map(do stuff)
However i haven't found a good way to apply these methods in a project. If i run the tests (they are inside the module) they all run smoothly since methods are added to base objects (arrays, strings and actual objects). But if i do the same thing in another project i get errors like Uncaught TypeError: Illegal invocation.
Could anyone please help me setup the package?
The way i'm trying to use redgem in projects right now is:
import redgem from 'redgem';
redgem():
Thanks.
So, basically this is how i export the module:
export default function apply () {
stringMethods.forEach((method) => {
String.prototype[method.name] = method.function
})
arrayMethods.forEach((method) => {
Array.prototype[method.name] = method.function
})
objectMethods.forEach((method) => {
Object.prototype[method.name] = method.function
})
}
Where every method is in the following form
{
// Tells wether the array is empty.
name: 'empty',
function: function () {
return this.length == 0
}
}

Object class couldn't be converted to string Laravel 5

When I return the request of my controller, I get:
{"employees":"3","reason":"common
reason","request":"5000","ded_per_pay":"500","months_to_pay":"2","date_issued":"2018-01-31"}
And in my create function, I get this error:
Object of class Symfony\Component\HttpFoundation\ParameterBag could not be converted to string
Here's my code:
CashAdvance::create([
'emp_id' => $request->employees,
'reason' => $request->reason,
'request' => $request->request,
'ded_per_pay' => $request->ded_per_pay,
'date_issued' => $request->date_issued,
'months_to_pay' => $request->months_to_pay
]);
What seems to be causing the problem??
This is really interesting. I've had a look in the API docs and it appears that the Request object has a parameter request. Which means that when you are calling $request->request, you are getting the parameter bag from your $request.
To get around this, you can use something like:
$myRequest = $request->input('request');
But I would heavily advise that instead you rename request to something that won't confuse yourself/other devs later in the project, and to keep these special named variables reserved for what they actually mean.

Property 'ensure' does not exist on type 'NodeRequire'

I'm trying webpack 2 code splitting.
According to this doc: https://webpack.js.org/guides/code-splitting-require/
the following code should include some.css into a new chunk named 'something'
require.ensure([], function(require) {
require('some.css');
}, 'something');
but when I run it, I get this error:
ERROR in ./src/index.ts
(4,9): error TS2339: Property 'ensure' does not exist on type 'NodeRequire'.
Any idea about how to fix it?
Thanks
The way I solved this was by creating my own interface - WebpackRequire - which extends NodeRequire with ensure1.
interface WebpackRequire extends NodeRequire {
ensure(
dependencies: string[],
callback: (require: WebpackRequire) => void,
errorCallback?: (error: Error) => void,
chunkName?: string
): void;
};
If you've only got a single instance of require.ensure, you can then type cast it to a WebpackRequire using (require as WebpackRequire).ensure, but since I used it multiple times in a module, I created local require at the top scope of the module, type cast as WebpackRequire, like this:
const require: WebpackRequire = (window as any).require;
1I got the types of ensure from the Webpack docs
I required a javascript document which then did the require. Not exactly the nicest solution, but it did work

Resources