diff --git a/packages/next/package.json b/packages/next/package.json index 5eb19eb1ddcff..86eb5cf15ca1b 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -234,7 +234,6 @@ "image-size": "1.0.0", "is-docker": "2.0.0", "is-wsl": "2.2.0", - "jest-docblock": "29.4.3", "jest-worker": "27.0.0-next.5", "json5": "2.2.3", "jsonwebtoken": "9.0.0", diff --git a/packages/next/src/build/swc/jest-transformer.ts b/packages/next/src/build/swc/jest-transformer.ts index d269113948866..350a8e2536db5 100644 --- a/packages/next/src/build/swc/jest-transformer.ts +++ b/packages/next/src/build/swc/jest-transformer.ts @@ -29,7 +29,6 @@ DEALINGS IN THE SOFTWARE. import vm from 'vm' import { transformSync } from './index' import { getJestSWCOptions } from './options' -import * as docblock from 'next/dist/compiled/jest-docblock' import type { TransformerCreator, TransformOptions, @@ -77,30 +76,16 @@ function isEsm( ) } -function getTestEnvironment( - src: string, - jestConfig: Config.ProjectConfig -): string { - const docblockPragmas = docblock.parse(docblock.extract(src)) - const pragma = docblockPragmas['jest-environment'] - const environment = - (Array.isArray(pragma) ? pragma[0] : pragma) ?? jestConfig.testEnvironment - return environment -} - const createTransformer: TransformerCreator< SyncTransformer, JestTransformerConfig > = (inputOptions) => ({ process(src, filename, jestOptions) { const jestConfig = getJestConfig(jestOptions) - const testEnvironment = getTestEnvironment(src, jestConfig) const swcTransformOpts = getJestSWCOptions({ - // When target is node it's similar to the server option set in SWC. - isServer: - testEnvironment === 'node' || - testEnvironment.includes('jest-environment-node'), + // Always target server when compiling during test, to pass server-only validations and allow testing pages with metadatas + isServer: true, filename, jsConfig: inputOptions?.jsConfig, resolvedBaseUrl: inputOptions?.resolvedBaseUrl, diff --git a/packages/next/src/compiled/jest-docblock/LICENSE b/packages/next/src/compiled/jest-docblock/LICENSE deleted file mode 100644 index b93be90515ccd..0000000000000 --- a/packages/next/src/compiled/jest-docblock/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) Meta Platforms, Inc. and affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/next/src/compiled/jest-docblock/index.js b/packages/next/src/compiled/jest-docblock/index.js deleted file mode 100644 index 240ca16b9aac3..0000000000000 --- a/packages/next/src/compiled/jest-docblock/index.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e={381:e=>{const detectNewline=e=>{if(typeof e!=="string"){throw new TypeError("Expected a string")}const t=e.match(/(?:\r?\n)/g)||[];if(t.length===0){return}const r=t.filter((e=>e==="\r\n")).length;const n=t.length-r;return r>n?"\r\n":"\n"};e.exports=detectNewline;e.exports.graceful=e=>typeof e==="string"&&detectNewline(e)||"\n"},37:e=>{e.exports=require("os")}};var t={};function __nccwpck_require__(r){var n=t[r];if(n!==undefined){return n.exports}var s=t[r]={exports:{}};var c=true;try{e[r](s,s.exports,__nccwpck_require__);c=false}finally{if(c)delete t[r]}return s.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r={};(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:true});e.extract=extract;e.parse=parse;e.parseWithComments=parseWithComments;e.print=print;e.strip=strip;function _os(){const e=__nccwpck_require__(37);_os=function(){return e};return e}function _detectNewline(){const e=_interopRequireDefault(__nccwpck_require__(381));_detectNewline=function(){return e};return e}function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const t=/\*\/$/;const n=/^\/\*\*?/;const s=/^\s*(\/\*\*?(.|\r?\n)*?\*\/)/;const c=/(^|\s+)\/\/([^\r\n]*)/g;const o=/^(\r?\n)+/;const i=/(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *(?![^@\r\n]*\/\/[^]*)([^@\r\n\s][^@\r\n]+?) *\r?\n/g;const a=/(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g;const u=/(\r?\n|^) *\* ?/g;const p=[];function extract(e){const t=e.match(s);return t?t[0].trimLeft():""}function strip(e){const t=e.match(s);return t&&t[0]?e.substring(t[0].length):e}function parse(e){return parseWithComments(e).pragmas}function parseWithComments(e){const r=(0,_detectNewline().default)(e)??_os().EOL;e=e.replace(n,"").replace(t,"").replace(u,"$1");let s="";while(s!==e){s=e;e=e.replace(i,`${r}$1 $2${r}`)}e=e.replace(o,"").trimRight();const _=Object.create(null);const l=e.replace(a,"").replace(o,"").trimRight();let f;while(f=a.exec(e)){const e=f[2].replace(c,"");if(typeof _[f[1]]==="string"||Array.isArray(_[f[1]])){_[f[1]]=p.concat(_[f[1]],e)}else{_[f[1]]=e}}return{comments:l,pragmas:_}}function print({comments:e="",pragmas:t={}}){const r=(0,_detectNewline().default)(e)??_os().EOL;const n="/**";const s=" *";const c=" */";const o=Object.keys(t);const i=o.map((e=>printKeyValues(e,t[e]))).reduce(((e,t)=>e.concat(t)),[]).map((e=>`${s} ${e}${r}`)).join("");if(!e){if(o.length===0){return""}if(o.length===1&&!Array.isArray(t[o[0]])){const e=t[o[0]];return`${n} ${printKeyValues(o[0],e)[0]}${c}`}}const a=e.split(r).map((e=>`${s} ${e}`)).join(r)+r;return n+r+(e?a:"")+(e&&o.length?s+r:"")+i+c}function printKeyValues(e,t){return p.concat(t).map((t=>`@${e} ${t}`.trim()))}})();module.exports=r})(); \ No newline at end of file diff --git a/packages/next/src/compiled/jest-docblock/package.json b/packages/next/src/compiled/jest-docblock/package.json deleted file mode 100644 index 78bc406c0d040..0000000000000 --- a/packages/next/src/compiled/jest-docblock/package.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"jest-docblock","main":"index.js","license":"MIT"} diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 722fd8e414b26..e337bf68fb8ce 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2179,15 +2179,6 @@ export async function ncc_https_proxy_agent(task, opts) { .target('src/compiled/https-proxy-agent') } -// eslint-disable-next-line camelcase -externals['jest-docblock'] = 'next/dist/compiled/jest-docblock' -export async function ncc_jest_docblock(task, opts) { - await task - .source(relative(__dirname, require.resolve('jest-docblock'))) - .ncc({ packageName: 'jest-docblock', externals }) - .target('src/compiled/jest-docblock') -} - export async function precompile(task, opts) { await task.parallel( [ @@ -2322,7 +2313,6 @@ export async function ncc(task, opts) { 'ncc_opentelemetry_api', 'ncc_http_proxy_agent', 'ncc_https_proxy_agent', - 'ncc_jest_docblock', 'ncc_mini_css_extract_plugin', ], opts diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index 2b68db6002606..d288bb92496df 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -454,8 +454,3 @@ declare module 'next/dist/compiled/@opentelemetry/api' { import * as m from '@opentelemetry/api' export = m } - -declare module 'next/dist/compiled/jest-docblock' { - import m from 'jest-docblock' - export = m -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d92cacb079e7c..98ff7be4c67a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1111,9 +1111,6 @@ importers: is-wsl: specifier: 2.2.0 version: 2.2.0 - jest-docblock: - specifier: 29.4.3 - version: 29.4.3 jest-worker: specifier: 27.0.0-next.5 version: 27.0.0-next.5 @@ -1224,7 +1221,7 @@ importers: version: 0.13.4 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.54.0)(webpack@5.86.0) + version: 12.4.0(webpack@5.86.0) schema-utils2: specifier: npm:schema-utils@2.7.1 version: /schema-utils@2.7.1 @@ -16160,13 +16157,6 @@ packages: detect-newline: 3.1.0 dev: true - /jest-docblock@29.4.3: - resolution: {integrity: sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - /jest-each@27.5.1: resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -23081,7 +23071,7 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - /sass-loader@12.4.0(sass@1.54.0)(webpack@5.86.0): + /sass-loader@12.4.0(webpack@5.86.0): resolution: {integrity: sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==} engines: {node: '>= 12.13.0'} peerDependencies: @@ -23099,7 +23089,6 @@ packages: dependencies: klona: 2.0.4 neo-async: 2.6.2 - sass: 1.54.0 webpack: 5.86.0(@swc/core@1.3.55) dev: true diff --git a/test/production/jest/server-only.test.ts b/test/production/jest/server-only.test.ts index 8cff3b170cfff..904ba30198dc6 100644 --- a/test/production/jest/server-only.test.ts +++ b/test/production/jest/server-only.test.ts @@ -8,10 +8,6 @@ describe('next/jest', () => { next = await createNext({ skipStart: true, files: { - 'app/page.jsx': `import { PI } from '../lib/util' - export default function Home() { - return

{PI}

- }`, 'app/layout.jsx': `export default function RootLayout({ children }) { return ( @@ -19,6 +15,12 @@ describe('next/jest', () => { ) }`, + + 'app/page.jsx': `import { PI } from '../lib/util' + export default function Home() { + return

{PI}

+ }`, + 'app/page.test.jsx': `import { render, screen } from '@testing-library/react' import '@testing-library/jest-dom' import Page from './page' @@ -27,13 +29,42 @@ describe('next/jest', () => { render() expect(screen.getByRole('heading')).toHaveTextContent('3.14') })`, - 'lib/util.js': `/** @jest-environment node */ + + 'app/[blog]/page.jsx': `import { Metadata } from 'next' + + export async function generateMetadata({ + params: { blog: title }, + }) { + return { title, description: 'A blog post about ' + title } + } + + export default function Page({ params }) { + return

All about {params.blog}

+ } + `, + + 'app/[blog]/page.test.jsx': `import { render, screen } from '@testing-library/react' + import '@testing-library/jest-dom' + import Page from './page' + + describe('Blog Page', () => { + it('has the appropriate title', () => { + render() + expect(screen.getByRole('heading')).toHaveTextContent('All about Jane') + }) + }) + `, + + 'lib/util.js': ` import 'server-only' export const PI = 3.14;`, - 'lib/utils.test.ts': `import { PI } from './util' + + 'lib/utils.test.ts': ` + import { PI } from './util' it('works from server-side code', () => { expect(PI).toEqual(3.14) })`, + 'jest.config.js': `module.exports = require('next/jest')({ dir: './' })({ testEnvironment: 'jsdom' })`, }, buildCommand: `yarn jest`, @@ -48,11 +79,11 @@ describe('next/jest', () => { afterAll(() => next.destroy()) - it('can run test against server side components', async () => { + it('can run test against server server only code', async () => { try { await next.start() } finally { - expect(next.cliOutput).toInclude('Tests: 2 passed, 2 total') + expect(next.cliOutput).toInclude('Tests: 3 passed, 3 total') } }) })