blitz-js / legacy-framework

MIT License
3 stars 2 forks source link

Index page test fails on newly generated app #293

Closed shishkin closed 2 years ago

shishkin commented 2 years ago

What is the problem?

I've enabled the skipped default test in app/pages/index.test.tsx and it fails. After adding the width and height attributes to the image, test keeps failing now complaining about wrong image source URL, which comes from the jest mock settings as test-file-stub.

Paste all your error logs here:

 FAIL   CLIENT  app/pages/index.test.tsx
  ● Console

    console.error
      Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot

      36 |     )
      37 |   }
    > 38 |   return defaultRender(ui, { wrapper, ...options })
         |          ^
      39 | }
      40 |
      41 | // --------------------------------------------------

      at printWarning (node_modules/react-dom/cjs/react-dom.development.js:77:30)
      at error (node_modules/react-dom/cjs/react-dom.development.js:51:7)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:29146:5)
      at node_modules/@testing-library/react/dist/pure.js:99:25
      at act (node_modules/react/cjs/react.development.js:2558:16)
      at render (node_modules/@testing-library/react/dist/pure.js:95:26)
      at render (test/utils.tsx:38:10)
      at Object.<anonymous> (app/pages/index.test.tsx:22:25)

    console.error
      Error: Uncaught [Error: Image with src "test-file-stub" must use "width" and "height" properties or "layout='fill'" property.]
          at reportException (.../blitzapp/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
          at innerInvokeEventListeners (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9)
          at invokeEventListeners (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
          at HTMLUnknownElementImpl._dispatch (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
          at HTMLUnknownElementImpl.dispatchEvent (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
          at HTMLUnknownElement.dispatchEvent (.../blitzapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
          at Object.invokeGuardedCallbackDev (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:4203:16)
          at invokeGuardedCallback (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:4265:31)
          at beginWork$1 (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:27094:7)
          at performUnitOfWork (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:26250:12) Error: Image with src "test-file-stub" must use "width" and "height" properties or "layout='fill'" property.
          at Image (.../blitzapp/node_modules/next/client/image.tsx:521:13)
          at renderWithHooks (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:15938:18)
          at mountIndeterminateComponent (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:20841:13)
          at beginWork (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:22325:16)
          at HTMLUnknownElement.callCallback (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:4154:14)
          at HTMLUnknownElement.callTheUserObjectsOperation (.../blitzapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
          at innerInvokeEventListeners (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25)
          at invokeEventListeners (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
          at HTMLUnknownElementImpl._dispatch (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
          at HTMLUnknownElementImpl.dispatchEvent (.../blitzapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
          at HTMLUnknownElement.dispatchEvent (.../blitzapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
          at Object.invokeGuardedCallbackDev (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:4203:16)
          at invokeGuardedCallback (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:4265:31)
          at beginWork$1 (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:27094:7)
          at performUnitOfWork (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:26250:12)
          at workLoopSync (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:26157:5)
          at renderRootSync (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:26121:7)
          at performSyncWorkOnRoot (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:25770:20)
          at flushSyncCallbacks (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:11806:22)
          at flushSync (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:25901:7)
          at legacyRenderSubtreeIntoContainer (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:29072:5)
          at Object.render (.../blitzapp/node_modules/react-dom/cjs/react-dom.development.js:29163:10)
          at .../blitzapp/node_modules/@testing-library/react/dist/pure.js:99:25
          at act (.../blitzapp/node_modules/react/cjs/react.development.js:2558:16)
          at render (.../blitzapp/node_modules/@testing-library/react/dist/pure.js:95:26)
          at render (.../blitzapp/test/utils.tsx:38:10)
          at Object.<anonymous> (.../blitzapp/app/pages/index.test.tsx:22:25)
          at Object.asyncJestTest (.../blitzapp/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
          at .../blitzapp/node_modules/jest-jasmine2/build/queueRunner.js:45:12
          at new Promise (<anonymous>)
          at mapper (.../blitzapp/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
          at .../blitzapp/node_modules/jest-jasmine2/build/queueRunner.js:75:41

      at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
      at reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:70:28)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)

    console.error
      The above error occurred in the <Image> component:

          at Image
          at div
          at main
          at div
          at Home
          at WithSuperJSON
          at Hydrate
          at QueryClientProvider
          at BlitzProvider
          at wrapper

      Consider adding an error boundary to your tree to customize error handling behavior.
      Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

      at logCapturedError (node_modules/react-dom/cjs/react-dom.development.js:18633:23)
      at update.callback (node_modules/react-dom/cjs/react-dom.development.js:18666:5)
      at callCallback (node_modules/react-dom/cjs/react-dom.development.js:13150:12)
      at commitUpdateQueue (node_modules/react-dom/cjs/react-dom.development.js:13171:9)
      at commitLayoutEffectOnFiber (node_modules/react-dom/cjs/react-dom.development.js:23151:13)
      at commitLayoutMountEffects_complete (node_modules/react-dom/cjs/react-dom.development.js:24417:9)
      at commitLayoutEffects_begin (node_modules/react-dom/cjs/react-dom.development.js:24403:7)
      at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:24341:3)

  ● renders blitz documentation link

    Image with src "test-file-stub" must use "width" and "height" properties or "layout='fill'" property.

      36 |     )
      37 |   }
    > 38 |   return defaultRender(ui, { wrapper, ...options })
         |          ^
      39 | }
      40 |
      41 | // --------------------------------------------------

      at Image (node_modules/next/client/image.tsx:521:13)
      at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:15938:18)
      at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:20841:13)
      at beginWork (node_modules/react-dom/cjs/react-dom.development.js:22325:16)
      at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:27070:14)
      at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:26250:12)
      at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:26157:5)
      at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:26121:7)
      at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:25770:20)
      at flushSyncCallbacks (node_modules/react-dom/cjs/react-dom.development.js:11806:22)
      at flushSync (node_modules/react-dom/cjs/react-dom.development.js:25901:7)
      at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:29072:5)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:29163:10)
      at node_modules/@testing-library/react/dist/pure.js:99:25
      at act (node_modules/react/cjs/react.development.js:2558:16)
      at render (node_modules/@testing-library/react/dist/pure.js:95:26)
      at render (test/utils.tsx:38:10)
      at Object.<anonymous> (app/pages/index.test.tsx:22:25)

Paste all relevant code snippets here:

What are detailed steps to reproduce this?

  1. Generate new blitz app with blitz new blitzapp
  2. Enable default skipped test in app/pages/index.test.tsx
  3. Run tests

Run blitz -v and paste the output here:

> blitz -v
macOS Big Sur | darwin-arm64 | Node: v16.9.1

blitz: 0.39.0 (global)
blitz: 0.39.0 (local)

  Package manager: yarn
  System:
    OS: macOS 11.6
    CPU: (8) arm64 Apple M1
    Memory: 470.52 MB / 16.00 GB
    Shell: 5.8 - /opt/homebrew/bin/zsh
  Binaries:
    Node: 16.9.1 - /opt/homebrew/bin/node
    Yarn: 1.22.11 - /opt/homebrew/bin/yarn
    npm: 7.24.0 - /opt/homebrew/bin/npm
    Watchman: Not Found
  npmPackages:
    @prisma/client: 2.31.0-integration-undici-4.3 => 2.31.0-integration-undici-4.3
    blitz: 0.39.0 => 0.39.0
    prisma: 2.31.0-integration-undici-4.3 => 2.31.0-integration-undici-4.3
    react: alpha => 18.0.0-alpha-9175f4d15-20210928
    react-dom: alpha => 18.0.0-alpha-9175f4d15-20210928
    typescript: ~4.3 => 4.3.5

Please include below any other applicable logs and screenshots that show your problem:

URL error after fixing image width and height:

Error: Uncaught [Error: Failed to parse src "test-file-stub" on `<Image>`, if using relative image it must start with a leading slash "/" or be an absolute URL (http:// or https://)]
beerose commented 2 years ago

The error comes with the file mock — it skips loading the real files and just returns a provided string ("test-file-stub" in this case), which is invalid src. Adding a manual mock to the test helps:

jest.mock("../../public/logo.png", () => {
  return "/public/logo.png"
})

We should fix the file mock by handling pngs in this way that it returns an object supported by next/image (the same as in runtime):

{
  type: {
    blurDataURL: "data:image/png;base64,...",
    height: 370,
    src: "/_next/static/image/public/logo.c7cef1afc7e012994ec94fb634b8f69a.png",
    width: 800
  }
}
shishkin commented 2 years ago

Thanks for the suggestion and triage @beerose!

The error comes with the file mock — it skips loading the real files and just returns a provided string ("test-file-stub" in this case), which is invalid src.

That relates to the second problem. But what about the error message with width and height?

I'm also not very clear why mocking is necessary for that test. Wouldn't it be beneficial to test the real image component with its source path and other attributes to e.g. verify that the source file exists?

beerose commented 2 years ago

But what about the error message with width and height?

Yeah, I forgot to include it. This mock should work:

jest.mock("../../public/logo.png", () => {
  return {
    default: { src: "/public/logo.png", height: 100, width: 100 },
  }
})

I'm also not very clear why mocking is necessary for that test. Wouldn't it be beneficial to test the real image component with its source path and other attributes to e.g. verify that the source file exists?

I agree with you. Alternatively, you could try using jest-webpack to make your tests more integration-like (testing webpack config and checking for actual images).

The current implementation is a suggested solution in both Next and Jest docs (they mention mocking static assets when using Jest with webpack). I guess the docs might be from before Next introduced next/image.

To get an actual image, we'd need to use webpack in our tests. However, webpack can be slow, so I don't think we want to do it.

Suggested solution:

  1. Add image-mock.js for images and return an object that is accepted by next/image: { src: "https://placekitten.com/100/100", width: 100, height: 100 }).
  2. Use image-mock.js for images in jest-preset.js.