質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Jest

Jestは、JavaScriptのテストフレームワークです。設定が不要で、高速且つ安全にテストを開始できます。コードカバレッジを生成できる他、テストスコープ外のオブジェクトを容易にモック化できるなど、豊富な機能によりテストの導入を簡単にします。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

4656閲覧

コンポーネントテストでエラー"TypeError: Cannot read property 'createElement' of undefined"の原因がわからない

_take

総合スコア1

Jest

Jestは、JavaScriptのテストフレームワークです。設定が不要で、高速且つ安全にテストを開始できます。コードカバレッジを生成できる他、テストスコープ外のオブジェクトを容易にモック化できるなど、豊富な機能によりテストの導入を簡単にします。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/08/05 13:28

編集2021/08/06 07:50

前提

React・テストコード初心者です。
親子関係のあるコンポーネントの中の
子コンポーネント内の静的メソッドのテストコードを作成しようとしています。
(jestとenzymeを使用)
子コンポーネントのマウントの記述でTypeError:となり、stackoverflowなどで検索をしてみたのですが、エラーが解消できませんでした。

エラーメッセージ

TypeError: Cannot read property 'createElement' of undefined 317 | 318 | return ( > 319 | <Wrapper ref={rootEl}>

該当のソースコード

テストコードは子コンポーネントだけをテストしようとしています。
enzymeのshallowも試しましたが同じエラーでテストが止まりました。

typescript

1//selectFile.spec.tsx 2import * as React from "react"; 3import { useSelector, useDispatch } from 'react-redux' 4import { SelectFile } from "./selectFile"; 5import { configure, mount } from "enzyme"; 6import * as Adapter from "enzyme-adapter-react-16"; 7import EnzymeToJson from "enzyme-to-json"; 8 9configure({ adapter: new Adapter() }); 10 11// useSelector,useDispatchのエラーが出たのでmock を追加 12jest.mock('src/selectors') 13jest.mock('react-redux') 14const useSelectorMock = useSelector as jest.Mock 15const useDispatchMock = useDispatch as jest.Mock 16const dummyProps = { 17 select: "basic", 18}; 19describe("dicom-uploader.ts", () => { 20 beforeEach(() => { 21 useSelectorMock.mockReturnValue(10) 22 useDispatchMock.mockReturnValue(jest.fn()) 23 }) 24 afterEach(() => { 25 jest.resetAllMocks(); 26 }) 27 it("should render default SelectFile", () => { 28 const mounted = mount(<SelectFile {...dummyProps} />); 29 // ↑でテストが止まります

コンポーネント(エラーなく動作している)

React

1// 親コンポーネント(一部抜粋) 2return ( 3 <Root> 4 {(() => { 5 switch(...){ 6 return <SelectFile />  // 今回テストしたいコンポーネント 7 default: 8 return <Foo /> 9 } 10 })()} 11 </Root> 12 );

React

1// SelectFile.tsx テストしたいコンポーネント(一部抜粋) 2import styled from "styled-components"; 3import ...省略 4 5const Wrapper = styled.div` 6...省略(cssプロパティ) 7`; 8 9export type Props = {...省略} 10export const SelectFile: React.FC<Props> = () => { 11 const rootEl = useRef<HTMLDivElement>(null); 12 13 const addFunc = (files: File) => { ...省略} // 新たに追加した関数をテストしたい 14 15 const something = useCallback( 16 // ...省略 17 const foo = addFunc(files); 18 ); 19 20 useEffect(() => { 21 return () => { 22 if (rootEl.current) { 23 const { current } = rootEl; 24 current.removeEventListener("drop", onDrop); 25 // ...省略 26 } 27 }; 28 }); 29 30 // その他useSelector、useEffect、useCallbackなどの記述 31 32 return ( 33 <Wrapper ref={rootEl}> <!-- テストではここでエラーとなっている --> 34 <!-- HTML要素、コンポーネントなど --> 35 </Wrapper> 36 ); 37}; 38 39export default DicomUploader;

試したこと

Reactの何かが読み込めていないためcreateElementがないというエラーになっていると考えました。
既存の構造の都合で子コンポーネントではsrc以外の場所からもファイルをimportしているため、パスの問題もあるかと思い、
jest.config.jsでモジュールのパス設定を変更してみました。しかし、エラーは解消されませんでした。

diff

1moduleNameMapper: { 2 "^.+\.svg$": "<rootDir>/mocks/icon-mock.tsx", 3 "^.+\.(css|less|scss)$": "identity-obj-proxy", 4+ "^src(.*)$": "<rootDir>/src$1", 5 }, 6+ moduleDirectories: ["node_modules", "<rootDir>/node_modules", "."],

補足情報

パッケージのバージョン

json

1// package.json 2"react": "16.13.1", 3"jest": "26.1.0", 4"enzyme": "3.11.0",

リポジトリ内ではreducerやstoreのテストコードは存在していて、テストはパスしています。
スナップショットも動作しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

マニュアルを読みましょう。関数コンポーネントの場合、refはそのままでは使えないとあります。
useRefで値を代入してください。

Ref と関数コンポーネント

投稿2021/08/05 15:36

FKM

総合スコア3647

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_take

2021/08/05 16:38

回答ありがとうございます。 理解がたりておらず恐縮です。 コンポーネントの中で<Wrapper ref={rootEl}>に対応する記述があります。 const rootEl = useRef<HTMLDivElement>(null); (rootEl.currentでイベントリスナー追加などをしている) この記述は「useRefで値を代入してください」とは異なっていることでしょうか。
FKM

2021/08/06 00:05 編集

それが通用するのはクラスコンポーネントの場合です。マニュアルには関数コンポーネントはそのままだと使用できないので、useRefを使用してくださいとありますよ。質問のプログラムにはuseRefの部分が見当たらないので、そう回答させていただきました。
_take

2021/08/06 07:57

質問の情報が少なくて大変失礼しました。 ソースコードを補足しましたのでご覧いただければと思います。 子コンポーネントのソースコードは、 Ref と関数コンポーネント中の「DOM 要素またはクラスコンポーネントを参照している」例に該当するかと思われます。
FKM

2021/08/06 08:55 編集

よく見たらWrapperって子コンポーネントですね。そこに定義しているのがまずいのでは? それだったら、Wrapperコンポーネント内の要素で定義したらどうでしょうか?
_take

2021/08/08 11:47

ご提案ありがとうございます。 Wrapperコンポーネント内の要素にrefを定義してみました。 <Wrapper>でエラーがでています。 TypeError: Cannot read property 'createElement' of undefined return ( > <Wrapper>   <div ref={rootEl}> 試しに<>で<Wrapper>をラップしたところ、<>でエラーがでています。
FKM

2021/08/08 12:28 編集

Wrapperタグはコンポーネント内だと不要なはずですよ。親コンポーネント内に子コンポーネントWrapperがあって、それを定義して、returnでその内容を返すので
_take

2021/08/10 04:21 編集

初心者の質問にお付き合いいただいて感謝しております。 Wrapperタグ=<Wrapper>で、<Wrapper>の記述を削除すればエラーが解消されるという認識であっていますか? returnの内容をdivタグだけにしてテストしてみたのですが、エラーの内容は変わりませんでした。 TypeError: Cannot read property 'createElement' of undefined return ( > <div></div> ); また、単純な構造のコンポーネントを作成してテストしてみたのですが、 同じエラーが出ているので環境などの方で問題があるのかもしれないです。 (3年くらい前に運用されているサービスのコードです) // コンポーネント import React from 'react'; export const Test = () => { return (<div><h1>Test</h1></div>) }; export default Test; // エラー TypeError: Cannot read property 'createElement' of undefined return ( > <div></div>
FKM

2021/08/10 04:26

あと、念の為確認ですが省略しているimportの部分にuseRefは書かれてますでしょうか。 tsじゃなくてjsの環境なら自分の方はそれでうまくいったので。
_take

2021/08/10 10:28

ご対応ありがとうございます。 ・省略しているimportの部分にuseRefが書かれているか→記述されているのを確認しました。 ・Qiita、Stack Overflow、GitHub→importに関しては同じ記述になっていることを確認しました。 おそらくですが下記の記事が当てはまる可能性がでてきました。 【テストしやすいRedux】<Provider>を切り出す https://qiita.com/impl_s/items/dd723a1707a5a07645d9 “<Provider>でラップされていない状態でコンポーネントがマウントするので、そのコンポーネント内でStoreの情報を使用していると当然テストは落ちてしまいます。” そもそものapp.tsxでProviderが使われていました。(ダイアログ表示など) export function App() { return ( <ConnectedRouter history={history}> <FooProvider> <DialogProvider> {Routes} <GlobalStyle /> </DialogProvider> </FooProvider> </ConnectedRouter> ); } 子コンポーネントで省略しているimportにダイアログ表示がありました。 importした内容をmockすることでエラーが回避できそうな気がします。(といってもmockの方法の調査からスタートです)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問