UNPKG

next-page-tester

Version:
184 lines (183 loc) 7.73 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setNextImageConfiguration = exports.glob = exports.getLocales = exports.isExternalRoute = exports.parseHTML = exports.executeWithFreshModules = exports.preservePredefinedSharedModulesIdentity = exports.useMountedState = exports.getPageExtensions = exports.findPagesDirectory = exports.defaultNextRoot = exports.removeFileExtension = exports.stringifyQueryString = exports.parseQueryString = exports.parseRoute = void 0; const url_1 = require("url"); const react_1 = require("react"); const querystring_1 = __importDefault(require("querystring")); const find_root_1 = __importDefault(require("find-root")); const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const stealthy_require_1 = __importDefault(require("stealthy-require")); const tiny_glob_1 = __importDefault(require("tiny-glob")); const normalize_path_1 = __importDefault(require("normalize-path")); const nextConfig_1 = require("./nextConfig"); const _error_1 = require("./_error"); const normalize_locale_path_1 = require("next/dist/shared/lib/i18n/normalize-locale-path"); const image_config_1 = require("next/dist/shared/lib/image-config"); function parseRoute({ route, }) { const { i18n } = (0, nextConfig_1.getNextConfig)(); const locales = i18n === null || i18n === void 0 ? void 0 : i18n.locales; const urlObject = new url_1.URL(`http://test.com${route}`); const { pathname: localePath } = urlObject; const { pathname, detectedLocale } = (0, normalize_locale_path_1.normalizeLocalePath)(localePath, locales); urlObject.pathname = pathname; /* * Next.js redirects by default routes with trailing slash to the counterpart without trailing slash * @NOTE: Here we might handle Next.js trailingSlash option * https://nextjs.org/docs/api-reference/next.config.js/trailing-slash */ if (pathname.endsWith('/') && pathname !== '/') { urlObject.pathname = pathname.slice(0, -1); } return { urlObject, detectedLocale }; } exports.parseRoute = parseRoute; function parseQueryString({ queryString, }) { const qs = queryString.startsWith('?') ? queryString.substring(1) : queryString; return querystring_1.default.parse(qs); } exports.parseQueryString = parseQueryString; function stringifyQueryString({ object, leadingQuestionMark, }) { const queryString = querystring_1.default.stringify(object); if (leadingQuestionMark && queryString) { return '?' + queryString; } return queryString; } exports.stringifyQueryString = stringifyQueryString; function removeFileExtension({ path }) { return path.replace(/\.[^/.]+$/, ''); } exports.removeFileExtension = removeFileExtension; exports.defaultNextRoot = (0, find_root_1.default)(process.cwd()); function findPagesDirectory({ nextRoot }) { const pagesPaths = [ path_1.default.join(nextRoot, 'pages'), path_1.default.join(nextRoot, 'src', 'pages'), ]; for (const path of pagesPaths) { if ((0, fs_1.existsSync)(path)) { return path; } } throw new _error_1.InternalError(`Cannot find "pages" directory under: ${nextRoot}`); } exports.findPagesDirectory = findPagesDirectory; function getPageExtensions() { const config = (0, nextConfig_1.getNextConfig)(); return config.pageExtensions; } exports.getPageExtensions = getPageExtensions; function useMountedState() { const mountedRef = (0, react_1.useRef)(false); const get = (0, react_1.useCallback)(() => mountedRef.current, []); (0, react_1.useEffect)(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }); return get; } exports.useMountedState = useMountedState; // @NOTE: It is crucial that these modules preserve their identity between client and server // for document rendering to work correctly. For things to kick in early enough in the process we // mark them as such in testHelpers. const predefinedSharedModules = [ 'react', 'next/dist/shared/lib/head-manager-context', 'next/dist/shared/lib/router-context', 'next/dist/shared/lib/runtime-config', ]; function preserveJestSharedModulesIdentity(modules) { for (const mockModuleName of modules) { // @NOTE for some reason Jest needs us to pre-import the modules // we want to require with jest.requireActual require(mockModuleName); jest.mock(mockModuleName, () => jest.requireActual(mockModuleName)); } } function preservePredefinedSharedModulesIdentity() { preserveJestSharedModulesIdentity(predefinedSharedModules); } exports.preservePredefinedSharedModulesIdentity = preservePredefinedSharedModulesIdentity; function executeWithFreshModules(f, { sharedModules }) { /* istanbul ignore else */ if (typeof jest !== 'undefined') { let result; preserveJestSharedModulesIdentity(sharedModules); jest.isolateModules(() => { result = f(); }); // @ts-expect-error result is surely defined here return result; } // @NOTE this branch will never be executed by Jest else { return (0, stealthy_require_1.default)(require.cache, f, () => { for (const moduleName of [ ...predefinedSharedModules, ...sharedModules, ]) { require(moduleName); } }, module); } } exports.executeWithFreshModules = executeWithFreshModules; function parseHTML(html) { const domParser = new DOMParser(); return domParser.parseFromString(html, 'text/html'); } exports.parseHTML = parseHTML; const ABSOLUTE_URL_REGEXP = new RegExp('^(?:[a-z]+:)?//', 'i'); function isExternalRoute(route) { return Boolean(route.match(ABSOLUTE_URL_REGEXP)); } exports.isExternalRoute = isExternalRoute; /** * Get locale information for a given route */ function getLocales({ pageObject: { detectedLocale }, }) { const { i18n } = (0, nextConfig_1.getNextConfig)(); return { locales: i18n === null || i18n === void 0 ? void 0 : i18n.locales, defaultLocale: i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale, locale: detectedLocale || (i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale), }; } exports.getLocales = getLocales; /** * Returns the absolute file paths matching a given glob pattern * It normalizes both incoming and outcoming paths */ async function glob(pattern) { const paths = await (0, tiny_glob_1.default)((0, normalize_path_1.default)(pattern), { absolute: true }); return paths.map((path) => (0, normalize_path_1.default)(path)); } exports.glob = glob; /** * Set next/image configuration as implemented in: * https://github.com/vercel/next.js/blob/v11.1.0/packages/next/client/image.tsx#L107 */ function setNextImageConfiguration() { const config = (0, nextConfig_1.getNextConfig)(); // @NOTE config.images is optional according to types but a default is always provided const imageConfig = config.images ? { deviceSizes: config.images.deviceSizes, imageSizes: config.images.imageSizes, path: config.images.path, loader: config.images.loader, domains: config.images.domains, } : /* istanbul ignore next */ image_config_1.imageConfigDefault; // @ts-expect-error this is how Next.js seems to do process.env.__NEXT_IMAGE_OPTS = imageConfig; } exports.setNextImageConfiguration = setNextImageConfiguration;