From 005b13f1ac182c8966c2bbf3bfddf1790e8b3f8d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 24 Aug 2021 07:52:45 -0500 Subject: [PATCH] Move unit tests to one folder and migrate them to TypeScript (#28427) * Move unit tests to one folder * Migrate unit tests to TypeScript * add test types to lint * Ensure ts(x) tests are run with util * Add tsx extension to jest config * bump --- .github/workflows/build_test_deploy.yml | 2 +- azure-pipelines.yml | 2 +- data.sqlite | 0 jest.config.js | 2 +- package.json | 14 ++-- run-tests.js | 75 ++++++++++-------- .../pnpm-support}/app/package.json | 0 .../pnpm-support}/app/pages/index.js | 0 .../pnpm-support}/test/index.test.js | 0 test/tsconfig.json | 14 ---- ...> babel-plugin-next-ssg-transform.test.ts} | 0 .../eslint-plugin-next/custom-pages/index.jsx | 0 .../custom-pages/list/[id].jsx | 0 .../google-font-display.test.ts} | 9 +-- .../google-font-preconnect.test.ts} | 9 +-- .../inline-script-id.test.ts} | 8 +- .../eslint-plugin-next/link-passhref.test.ts} | 9 +-- .../next-script-for-ga.test.ts} | 17 ++-- .../eslint-plugin-next/no-css-tags.test.ts} | 9 +-- .../no-document-import-in-page.test.ts} | 10 +-- .../no-duplicate-head.test.ts} | 10 +-- .../no-head-import-in-document.test.ts} | 10 +-- .../no-html-link-for-pages.test.ts} | 10 +-- .../no-img-element.test.ts} | 10 +-- .../no-page-custom-font.test.ts} | 11 ++- .../no-script-in-document.test.ts} | 10 +-- .../no-script-in-head.test.ts} | 9 +-- .../no-sync-scripts.test.ts} | 10 +-- .../no-title-in-document-head.test.ts} | 9 +-- .../eslint-plugin-next/no-typos.test.ts} | 11 ++- .../no-unwanted-polyfillio.test.ts} | 10 +-- ...onfig.unit.test.js => find-config.test.ts} | 0 ...le.unit.test.js => find-page-file.test.ts} | 2 +- ... get-node-options-without-inspect.test.ts} | 0 ...me.unit.test.js => getDisplayName.test.ts} | 2 +- ...escape.unit.test.js => htmlescape.test.ts} | 0 .../detect-content-type.test.ts} | 10 +-- .../image-optimizer/get-max-age.test.ts} | 2 +- .../unit/image-optimizer/images/animated.webp | Bin 0 -> 37342 bytes test/unit/image-optimizer/images/test.jpg | Bin 0 -> 6765 bytes test/unit/image-optimizer/images/test.png | Bin 0 -> 1545 bytes test/unit/image-optimizer/images/test.svg | 13 +++ ...g.unit.test.js => image-rendering.test.ts} | 0 ....test.js => is-serializable-props.test.ts} | 8 +- test/{ => unit}/isolated/.gitignore | 0 .../isolated/_resolvedata/.gitignore | 0 .../isolated/_resolvedata/aa/cache.js | 0 .../isolated/_resolvedata/aa/index.js | 0 .../isolated/_resolvedata/bb/index.json | 0 .../isolated/_resolvedata/cache/test.txt | 0 .../isolated/_resolvedata/cc/index.js | 0 .../isolated/_resolvedata/cc/index.json | 0 .../invalid-target/next.config.js | 0 .../_resolvedata/js-ts-config/next.config.js | 0 .../js-ts-config/next.config.json | 0 .../_resolvedata/js-ts-config/next.config.jsx | 0 .../_resolvedata/js-ts-config/next.config.ts | 0 .../_resolvedata/js-ts-config/next.config.tsx | 0 test/{ => unit}/isolated/_resolvedata/one.js | 0 .../{ => unit}/isolated/_resolvedata/one.json | 0 .../_resolvedata/readdir/pages/index.js | 0 .../_resolvedata/readdir/pages/nav/about.js | 0 .../_resolvedata/readdir/pages/nav/index.js | 0 .../readdir/pages/nav/products/product.js | 0 .../readdir/pages/nested/index.js | 0 .../_resolvedata/readdir/pages/prefered.js | 0 .../readdir/pages/prefered/index.js | 0 .../_resolvedata/server/pages-manifest.json | 0 .../server/static/development/pages/_error.js | 0 .../server/static/development/pages/index.js | 0 .../development/pages/non-existent-child.js | 0 .../server/static/development/pages/world.js | 0 .../{ => unit}/isolated/_resolvedata/two.json | 0 .../typescript-config/next.config.ts | 0 .../_resolvedata/valid-target/next.config.js | 0 .../_resolvedata/with-function/next.config.js | 0 .../without-function/next.config.js | 0 .../isolated/config.test.ts} | 0 .../isolated/require-page.test.ts} | 20 ++--- ...ng.unit.test.js => link-rendering.test.ts} | 0 ...arnings.test.js => link-warnings.test.tsx} | 0 ...it.test.js => loadGetInitialProps.test.ts} | 12 +-- test/unit/{mitt.unit.test.js => mitt.test.ts} | 0 ...unit.test.js => next-babel-loader.test.ts} | 16 ++-- ...-babel.unit.test.js => next-babel.test.ts} | 6 +- ...-dynamic.test.js => next-dynamic.test.tsx} | 0 ...it.test.js => next-head-rendering.test.ts} | 2 +- ...unit.test.js => next-server-utils.test.ts} | 0 ...next-swc.unit.test.js => next-swc.test.ts} | 0 ...omma.unit.test.js => oxford-comma.test.ts} | 0 ...unit.test.js => page-route-sorter.test.ts} | 0 ...nit.test.js => parse-relative-url.test.ts} | 6 +- ...ts.unit.test.js => phaseConstants.test.ts} | 0 ...py.unit.test.js => recursive-copy.test.ts} | 0 ....unit.test.js => recursive-delete.test.ts} | 6 +- ...unit.test.js => recursive-readdir.test.ts} | 2 +- ...t.test.js => router-add-base-path.test.ts} | 0 ...st.js => webpack-config-overrides.test.ts} | 0 tsconfig.json | 19 +++++ 99 files changed, 202 insertions(+), 214 deletions(-) delete mode 100644 data.sqlite rename test/{package-managers/pnpm => integration/pnpm-support}/app/package.json (100%) rename test/{package-managers/pnpm => integration/pnpm-support}/app/pages/index.js (100%) rename test/{package-managers/pnpm => integration/pnpm-support}/test/index.test.js (100%) delete mode 100644 test/tsconfig.json rename test/unit/{babel-plugin-next-ssg-transform.unit.test.js => babel-plugin-next-ssg-transform.test.ts} (100%) rename test/{ => unit}/eslint-plugin-next/custom-pages/index.jsx (100%) rename test/{ => unit}/eslint-plugin-next/custom-pages/list/[id].jsx (100%) rename test/{eslint-plugin-next/google-font-display.unit.test.js => unit/eslint-plugin-next/google-font-display.test.ts} (94%) rename test/{eslint-plugin-next/google-font-preconnect.unit.test.js => unit/eslint-plugin-next/google-font-preconnect.test.ts} (87%) rename test/{eslint-plugin-next/inline-script-id.unit.test.js => unit/eslint-plugin-next/inline-script-id.test.ts} (95%) rename test/{eslint-plugin-next/link-passhref.unit.test.js => unit/eslint-plugin-next/link-passhref.test.ts} (88%) rename test/{eslint-plugin-next/next-script-for-ga.unit.test.js => unit/eslint-plugin-next/next-script-for-ga.test.ts} (97%) rename test/{eslint-plugin-next/no-css-tags.unit.test.js => unit/eslint-plugin-next/no-css-tags.test.ts} (92%) rename test/{eslint-plugin-next/no-document-import-in-page.unit.test.js => unit/eslint-plugin-next/no-document-import-in-page.test.ts} (91%) rename test/{eslint-plugin-next/no-duplicate-head.test.js => unit/eslint-plugin-next/no-duplicate-head.test.ts} (94%) rename test/{eslint-plugin-next/no-head-import-in-document.unit.test.js => unit/eslint-plugin-next/no-head-import-in-document.test.ts} (95%) rename test/{eslint-plugin-next/no-html-link-for-pages.unit.test.js => unit/eslint-plugin-next/no-html-link-for-pages.test.ts} (94%) rename test/{eslint-plugin-next/no-img-element.test.js => unit/eslint-plugin-next/no-img-element.test.ts} (85%) rename test/{eslint-plugin-next/no-page-custom-font.unit.test.js => unit/eslint-plugin-next/no-page-custom-font.test.ts} (92%) rename test/{eslint-plugin-next/no-script-in-document.test.js => unit/eslint-plugin-next/no-script-in-document.test.ts} (92%) rename test/{eslint-plugin-next/no-script-in-head.test.js => unit/eslint-plugin-next/no-script-in-head.test.ts} (82%) rename test/{eslint-plugin-next/no-sync-scripts.unit.test.js => unit/eslint-plugin-next/no-sync-scripts.test.ts} (90%) rename test/{eslint-plugin-next/no-title-in-document-head.unit.test.js => unit/eslint-plugin-next/no-title-in-document-head.test.ts} (85%) rename test/{eslint-plugin-next/no-typos.test.js => unit/eslint-plugin-next/no-typos.test.ts} (94%) rename test/{eslint-plugin-next/no-unwanted-polyfillio.unit.test.js => unit/eslint-plugin-next/no-unwanted-polyfillio.test.ts} (91%) rename test/unit/{find-config.unit.test.js => find-config.test.ts} (100%) rename test/unit/{find-page-file.unit.test.js => find-page-file.test.ts} (93%) rename test/unit/{get-node-options-without-inspect.unit.test.js => get-node-options-without-inspect.test.ts} (100%) rename test/unit/{getDisplayName.unit.test.js => getDisplayName.test.ts} (93%) rename test/unit/{htmlescape.unit.test.js => htmlescape.test.ts} (100%) rename test/{integration/image-optimizer/test/detect-content-type.unit.test.js => unit/image-optimizer/detect-content-type.test.ts} (64%) rename test/{integration/image-optimizer/test/get-max-age.unit.test.js => unit/image-optimizer/get-max-age.test.ts} (94%) create mode 100644 test/unit/image-optimizer/images/animated.webp create mode 100644 test/unit/image-optimizer/images/test.jpg create mode 100644 test/unit/image-optimizer/images/test.png create mode 100644 test/unit/image-optimizer/images/test.svg rename test/unit/{image-rendering.unit.test.js => image-rendering.test.ts} (100%) rename test/unit/{is-serializable-props.unit.test.js => is-serializable-props.test.ts} (97%) rename test/{ => unit}/isolated/.gitignore (100%) rename test/{ => unit}/isolated/_resolvedata/.gitignore (100%) rename test/{ => unit}/isolated/_resolvedata/aa/cache.js (100%) rename test/{ => unit}/isolated/_resolvedata/aa/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/bb/index.json (100%) rename test/{ => unit}/isolated/_resolvedata/cache/test.txt (100%) rename test/{ => unit}/isolated/_resolvedata/cc/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/cc/index.json (100%) rename test/{ => unit}/isolated/_resolvedata/invalid-target/next.config.js (100%) rename test/{ => unit}/isolated/_resolvedata/js-ts-config/next.config.js (100%) rename test/{ => unit}/isolated/_resolvedata/js-ts-config/next.config.json (100%) rename test/{ => unit}/isolated/_resolvedata/js-ts-config/next.config.jsx (100%) rename test/{ => unit}/isolated/_resolvedata/js-ts-config/next.config.ts (100%) rename test/{ => unit}/isolated/_resolvedata/js-ts-config/next.config.tsx (100%) rename test/{ => unit}/isolated/_resolvedata/one.js (100%) rename test/{ => unit}/isolated/_resolvedata/one.json (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/nav/about.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/nav/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/nav/products/product.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/nested/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/prefered.js (100%) rename test/{ => unit}/isolated/_resolvedata/readdir/pages/prefered/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/server/pages-manifest.json (100%) rename test/{ => unit}/isolated/_resolvedata/server/static/development/pages/_error.js (100%) rename test/{ => unit}/isolated/_resolvedata/server/static/development/pages/index.js (100%) rename test/{ => unit}/isolated/_resolvedata/server/static/development/pages/non-existent-child.js (100%) rename test/{ => unit}/isolated/_resolvedata/server/static/development/pages/world.js (100%) rename test/{ => unit}/isolated/_resolvedata/two.json (100%) rename test/{ => unit}/isolated/_resolvedata/typescript-config/next.config.ts (100%) rename test/{ => unit}/isolated/_resolvedata/valid-target/next.config.js (100%) rename test/{ => unit}/isolated/_resolvedata/with-function/next.config.js (100%) rename test/{ => unit}/isolated/_resolvedata/without-function/next.config.js (100%) rename test/{isolated/config.unit.test.js => unit/isolated/config.test.ts} (100%) rename test/{isolated/require-page.unit.test.js => unit/isolated/require-page.test.ts} (83%) rename test/unit/{link-rendering.unit.test.js => link-rendering.test.ts} (100%) rename test/unit/{link-warnings.test.js => link-warnings.test.tsx} (100%) rename test/unit/{loadGetInitialProps.unit.test.js => loadGetInitialProps.test.ts} (80%) rename test/unit/{mitt.unit.test.js => mitt.test.ts} (100%) rename test/unit/{next-babel-loader.unit.test.js => next-babel-loader.test.ts} (98%) rename test/unit/{next-babel.unit.test.js => next-babel.test.ts} (98%) rename test/unit/{next-dynamic.test.js => next-dynamic.test.tsx} (100%) rename test/unit/{next-head-rendering.unit.test.js => next-head-rendering.test.ts} (91%) rename test/unit/{next-server-utils.unit.test.js => next-server-utils.test.ts} (100%) rename test/unit/{next-swc.unit.test.js => next-swc.test.ts} (100%) rename test/unit/{oxford-comma.unit.test.js => oxford-comma.test.ts} (100%) rename test/unit/{page-route-sorter.unit.test.js => page-route-sorter.test.ts} (100%) rename test/unit/{parse-relative-url.unit.test.js => parse-relative-url.test.ts} (96%) rename test/unit/{phaseConstants.unit.test.js => phaseConstants.test.ts} (100%) rename test/unit/{recursive-copy.unit.test.js => recursive-copy.test.ts} (100%) rename test/unit/{recursive-delete.unit.test.js => recursive-delete.test.ts} (84%) rename test/unit/{recursive-readdir.unit.test.js => recursive-readdir.test.ts} (91%) rename test/unit/{router-add-base-path.unit.test.js => router-add-base-path.test.ts} (100%) rename test/unit/{webpack-config-overrides.unit.test.js => webpack-config-overrides.test.ts} (100%) create mode 100644 tsconfig.json diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index ff818d20c6..3a00a6f0f0 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -104,7 +104,7 @@ jobs: path: ./* key: ${{ github.sha }} - - run: node run-tests.js --timings --type unit -g 1/1 + - run: node run-tests.js --type unit if: ${{needs.build.outputs.docsChange != 'docs only change'}} testIntegration: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 37fd3bc6bd..dc023d9781 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -111,7 +111,7 @@ stages: path: $(System.DefaultWorkingDirectory) displayName: Cache Build - script: | - node run-tests.js -g 1/1 --timings --azure --type unit + node run-tests.js --type unit displayName: 'Run tests' # TODO: investigate re-enabling when stability matches running in # tests in ubuntu environment diff --git a/data.sqlite b/data.sqlite deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/jest.config.js b/jest.config.js index 4476f90967..ef7dc72d83 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - testMatch: ['**/*.test.js'], + testMatch: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'], verbose: true, rootDir: 'test', modulePaths: ['/lib'], diff --git a/package.json b/package.json index 3c91d06533..bd737c8d98 100644 --- a/package.json +++ b/package.json @@ -10,22 +10,18 @@ "lerna": "lerna", "dev": "lerna run dev --stream --parallel", "dev2": "while true; do yarn --check-files && yarn dev; done", - "testonly": "jest --runInBand", + "test-types": "yarn tsc", + "test-unit": "yarn jest test/unit/", + "testonly": "yarn jest --runInBand", "testheadless": "cross-env HEADLESS=true yarn testonly", - "testsafari": "cross-env BROWSER_NAME=safari yarn testonly", - "testfirefox": "cross-env BROWSER_NAME=firefox yarn testonly", - "testie": "cross-env BROWSER_NAME=\"internet explorer\" yarn testonly", - "testall": "yarn run testonly -- --ci --forceExit && lerna run --scope @next/codemod test", + "testall": "yarn test -- --ci --forceExit && lerna run --scope @next/codemod test", "genstats": "cross-env LOCAL_STATS=true node .github/actions/next-stats-action/src/index.js", - "pretest": "yarn run lint", "git-reset": "git reset --hard HEAD", "git-clean": "git clean -d -x -e node_modules -e packages -f", - "test-take2": "yarn git-reset && yarn git-clean && yarn testall", - "test": "yarn run testall || yarn run test-take2", "lint-typescript": "lerna run typescript", "lint-eslint": "eslint . --ext js,jsx,ts,tsx --max-warnings=0", "lint-no-typescript": "run-p prettier-check lint-eslint", - "lint": "run-p lint-typescript prettier-check lint-eslint lint-language", + "lint": "run-p test-types lint-typescript prettier-check lint-eslint lint-language", "lint-fix": "yarn prettier-fix && eslint . --ext js,jsx,ts,tsx --fix --max-warnings=0", "lint-language": "alex .", "prettier-check": "prettier --check .", diff --git a/run-tests.js b/run-tests.js index 1eb18a9c4a..bb9a790d2c 100644 --- a/run-tests.js +++ b/run-tests.js @@ -12,16 +12,12 @@ const glob = promisify(_glob) const exec = promisify(execOrig) const timings = [] -const NUM_RETRIES = 2 +const DEFAULT_NUM_RETRIES = 2 const DEFAULT_CONCURRENCY = 2 const RESULTS_EXT = `.results.json` const isTestJob = !!process.env.NEXT_TEST_JOB const TIMINGS_API = `https://next-timings.jjsweb.site/api/timings` -const UNIT_TEST_EXT = '.unit.test.js' -const DEV_TEST_EXT = '.dev.test.js' -const PROD_TEST_EXT = '.prod.test.js' - const NON_CONCURRENT_TESTS = [ 'test/integration/basic/test/index.test.js', 'test/acceptance/ReactRefresh.dev.test.js', @@ -30,12 +26,17 @@ const NON_CONCURRENT_TESTS = [ 'test/acceptance/ReactRefreshRequire.dev.test.js', ] +const testFilters = { + unit: 'unit/', +} + // which types we have configured to run separate -const configuredTestTypes = [UNIT_TEST_EXT] +const configuredTestTypes = Object.values(testFilters) async function main() { + let numRetries = DEFAULT_NUM_RETRIES let concurrencyIdx = process.argv.indexOf('-c') - const concurrency = + let concurrency = parseInt(process.argv[concurrencyIdx + 1], 10) || DEFAULT_CONCURRENCY const outputTimings = process.argv.indexOf('--timings') !== -1 @@ -50,15 +51,17 @@ async function main() { let filterTestsBy switch (testType) { - case 'unit': - filterTestsBy = UNIT_TEST_EXT - break - case 'dev': - filterTestsBy = DEV_TEST_EXT - break - case 'production': - filterTestsBy = PROD_TEST_EXT + case 'unit': { + numRetries = 0 + filterTestsBy = testFilters.unit break + } + // case 'dev': + // filterTestsBy = DEV_TEST_EXT + // break + // case 'production': + // filterTestsBy = PROD_TEST_EXT + // break case 'all': filterTestsBy = 'none' break @@ -67,22 +70,22 @@ async function main() { } console.log('Running tests with concurrency:', concurrency) - let tests = process.argv.filter((arg) => arg.endsWith('.test.js')) + let tests = process.argv.filter((arg) => arg.match(/\.test\.(js|ts|tsx)/)) let prevTimings if (tests.length === 0) { tests = ( - await glob('**/*.test.js', { + await glob('**/*.test.{js,ts,tsx}', { nodir: true, cwd: path.join(__dirname, 'test'), }) ).filter((test) => { - // only include the specified type if (filterTestsBy) { - return filterTestsBy === 'none' ? true : test.endsWith(filterTestsBy) - // include all except the separately configured types + // only include the specified type + return filterTestsBy === 'none' ? true : test.startsWith(filterTestsBy) } else { - return !configuredTestTypes.some((type) => test.endsWith(type)) + // include all except the separately configured types + return !configuredTestTypes.some((type) => test.startsWith(type)) } }) @@ -183,7 +186,7 @@ async function main() { ) const children = new Set() - const runTest = (test = '', usePolling) => + const runTest = (test = '', usePolling, isFinalRun) => new Promise((resolve, reject) => { const start = new Date().getTime() let outputChunks = [] @@ -232,7 +235,9 @@ async function main() { child.on('exit', (code) => { children.delete(child) if (code) { - outputChunks.forEach((chunk) => process.stdout.write(chunk)) + if (isFinalRun) { + outputChunks.forEach((chunk) => process.stdout.write(chunk)) + } reject(new Error(`failed with code: ${code}`)) } resolve(new Date().getTime() - start) @@ -254,21 +259,21 @@ async function main() { for (const test of nonConcurrentTestNames) { let passed = false - for (let i = 0; i < NUM_RETRIES + 1; i++) { + for (let i = 0; i < numRetries + 1; i++) { try { - console.log(`Starting ${test} retry ${i}/${NUM_RETRIES}`) - const time = await runTest(test, i > 0) + console.log(`Starting ${test} retry ${i}/${numRetries}`) + const time = await runTest(test, i > 0, i === numRetries) timings.push({ file: test, time, }) passed = true console.log( - `Finished ${test} on retry ${i}/${NUM_RETRIES} in ${time / 1000}s` + `Finished ${test} on retry ${i}/${numRetries} in ${time / 1000}s` ) break } catch (err) { - if (i < NUM_RETRIES) { + if (i < numRetries) { try { const testDir = path.dirname(path.join(__dirname, test)) console.log('Cleaning test files at', testDir) @@ -279,7 +284,7 @@ async function main() { } } if (!passed) { - console.error(`${test} failed to pass within ${NUM_RETRIES} retries`) + console.error(`${test} failed to pass within ${numRetries} retries`) children.forEach((child) => child.kill()) if (isTestJob) { @@ -303,21 +308,21 @@ async function main() { await sema.acquire() let passed = false - for (let i = 0; i < NUM_RETRIES + 1; i++) { + for (let i = 0; i < numRetries + 1; i++) { try { - console.log(`Starting ${test} retry ${i}/${NUM_RETRIES}`) - const time = await runTest(test, i > 0) + console.log(`Starting ${test} retry ${i}/${numRetries}`) + const time = await runTest(test, i > 0, i === numRetries) timings.push({ file: test, time, }) passed = true console.log( - `Finished ${test} on retry ${i}/${NUM_RETRIES} in ${time / 1000}s` + `Finished ${test} on retry ${i}/${numRetries} in ${time / 1000}s` ) break } catch (err) { - if (i < NUM_RETRIES) { + if (i < numRetries) { try { const testDir = path.dirname(path.join(__dirname, test)) console.log('Cleaning test files at', testDir) @@ -328,7 +333,7 @@ async function main() { } } if (!passed) { - console.error(`${test} failed to pass within ${NUM_RETRIES} retries`) + console.error(`${test} failed to pass within ${numRetries} retries`) children.forEach((child) => child.kill()) if (isTestJob) { diff --git a/test/package-managers/pnpm/app/package.json b/test/integration/pnpm-support/app/package.json similarity index 100% rename from test/package-managers/pnpm/app/package.json rename to test/integration/pnpm-support/app/package.json diff --git a/test/package-managers/pnpm/app/pages/index.js b/test/integration/pnpm-support/app/pages/index.js similarity index 100% rename from test/package-managers/pnpm/app/pages/index.js rename to test/integration/pnpm-support/app/pages/index.js diff --git a/test/package-managers/pnpm/test/index.test.js b/test/integration/pnpm-support/test/index.test.js similarity index 100% rename from test/package-managers/pnpm/test/index.test.js rename to test/integration/pnpm-support/test/index.test.js diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index 8d123caf24..0000000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "es6", - "allowJs": true, - "noEmit": true, - "baseUrl": "../", - "paths": { - "next-test-utils": ["./test/lib/next-test-utils"], - "amp-test-utils": ["./test/lib/amp-test-utils"], - "next-webdriver": ["./test/lib/next-webdriver"] - } - } -} diff --git a/test/unit/babel-plugin-next-ssg-transform.unit.test.js b/test/unit/babel-plugin-next-ssg-transform.test.ts similarity index 100% rename from test/unit/babel-plugin-next-ssg-transform.unit.test.js rename to test/unit/babel-plugin-next-ssg-transform.test.ts diff --git a/test/eslint-plugin-next/custom-pages/index.jsx b/test/unit/eslint-plugin-next/custom-pages/index.jsx similarity index 100% rename from test/eslint-plugin-next/custom-pages/index.jsx rename to test/unit/eslint-plugin-next/custom-pages/index.jsx diff --git a/test/eslint-plugin-next/custom-pages/list/[id].jsx b/test/unit/eslint-plugin-next/custom-pages/list/[id].jsx similarity index 100% rename from test/eslint-plugin-next/custom-pages/list/[id].jsx rename to test/unit/eslint-plugin-next/custom-pages/list/[id].jsx diff --git a/test/eslint-plugin-next/google-font-display.unit.test.js b/test/unit/eslint-plugin-next/google-font-display.test.ts similarity index 94% rename from test/eslint-plugin-next/google-font-display.unit.test.js rename to test/unit/eslint-plugin-next/google-font-display.test.ts index 6a1f0b543b..60d9576566 100644 --- a/test/eslint-plugin-next/google-font-display.unit.test.js +++ b/test/unit/eslint-plugin-next/google-font-display.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/google-font-display') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/google-font-display' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2020, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('google-font-display', rule, { valid: [ `import Head from "next/head"; diff --git a/test/eslint-plugin-next/google-font-preconnect.unit.test.js b/test/unit/eslint-plugin-next/google-font-preconnect.test.ts similarity index 87% rename from test/eslint-plugin-next/google-font-preconnect.unit.test.js rename to test/unit/eslint-plugin-next/google-font-preconnect.test.ts index b77e923a5b..178b17eede 100644 --- a/test/eslint-plugin-next/google-font-preconnect.unit.test.js +++ b/test/unit/eslint-plugin-next/google-font-preconnect.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/google-font-preconnect') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/google-font-preconnect' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2020, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('google-font-preconnect', rule, { valid: [ `export const Test = () => ( diff --git a/test/eslint-plugin-next/inline-script-id.unit.test.js b/test/unit/eslint-plugin-next/inline-script-id.test.ts similarity index 95% rename from test/eslint-plugin-next/inline-script-id.unit.test.js rename to test/unit/eslint-plugin-next/inline-script-id.test.ts index 222b78b71c..eb59af7744 100644 --- a/test/eslint-plugin-next/inline-script-id.unit.test.js +++ b/test/unit/eslint-plugin-next/inline-script-id.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/inline-script-id') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/inline-script-id' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', diff --git a/test/eslint-plugin-next/link-passhref.unit.test.js b/test/unit/eslint-plugin-next/link-passhref.test.ts similarity index 88% rename from test/eslint-plugin-next/link-passhref.unit.test.js rename to test/unit/eslint-plugin-next/link-passhref.test.ts index 398f14e805..b493ceafba 100644 --- a/test/eslint-plugin-next/link-passhref.unit.test.js +++ b/test/unit/eslint-plugin-next/link-passhref.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/link-passhref') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/link-passhref' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('link-passhref', rule, { valid: [ `export const Home = () => ( diff --git a/test/eslint-plugin-next/next-script-for-ga.unit.test.js b/test/unit/eslint-plugin-next/next-script-for-ga.test.ts similarity index 97% rename from test/eslint-plugin-next/next-script-for-ga.unit.test.js rename to test/unit/eslint-plugin-next/next-script-for-ga.test.ts index eb4c01fd92..8200e4aab5 100644 --- a/test/eslint-plugin-next/next-script-for-ga.unit.test.js +++ b/test/unit/eslint-plugin-next/next-script-for-ga.test.ts @@ -1,11 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/next-script-for-ga') - -const RuleTester = require('eslint').RuleTester - -const ERROR_MSG = - 'Use the `next/script` component for loading third party scripts. See: https://nextjs.org/docs/messages/next-script-for-ga.' - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/next-script-for-ga' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -16,7 +11,11 @@ RuleTester.setDefaultConfig({ }, }) -var ruleTester = new RuleTester() +const ERROR_MSG = + 'Use the `next/script` component for loading third party scripts. See: https://nextjs.org/docs/messages/next-script-for-ga.' + +const ruleTester = new RuleTester() + ruleTester.run('sync-scripts', rule, { valid: [ `import Script from 'next/script' diff --git a/test/eslint-plugin-next/no-css-tags.unit.test.js b/test/unit/eslint-plugin-next/no-css-tags.test.ts similarity index 92% rename from test/eslint-plugin-next/no-css-tags.unit.test.js rename to test/unit/eslint-plugin-next/no-css-tags.test.ts index df38b896ca..c8312fb452 100644 --- a/test/eslint-plugin-next/no-css-tags.unit.test.js +++ b/test/unit/eslint-plugin-next/no-css-tags.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-css-tags') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-css-tags' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-css-tags', rule, { valid: [ `import {Head} from 'next/document'; diff --git a/test/eslint-plugin-next/no-document-import-in-page.unit.test.js b/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts similarity index 91% rename from test/eslint-plugin-next/no-document-import-in-page.unit.test.js rename to test/unit/eslint-plugin-next/no-document-import-in-page.test.ts index fc8a28ca5c..29b536c292 100644 --- a/test/eslint-plugin-next/no-document-import-in-page.unit.test.js +++ b/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-document-import-in-page') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-document-import-in-page' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-document-import-in-page', rule, { valid: [ { diff --git a/test/eslint-plugin-next/no-duplicate-head.test.js b/test/unit/eslint-plugin-next/no-duplicate-head.test.ts similarity index 94% rename from test/eslint-plugin-next/no-duplicate-head.test.js rename to test/unit/eslint-plugin-next/no-duplicate-head.test.ts index 579865966c..194ea827f8 100644 --- a/test/eslint-plugin-next/no-duplicate-head.test.js +++ b/test/unit/eslint-plugin-next/no-duplicate-head.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-duplicate-head') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-duplicate-head' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-duplicate-head', rule, { valid: [ { diff --git a/test/eslint-plugin-next/no-head-import-in-document.unit.test.js b/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts similarity index 95% rename from test/eslint-plugin-next/no-head-import-in-document.unit.test.js rename to test/unit/eslint-plugin-next/no-head-import-in-document.test.ts index 12cee4a468..f6840651e8 100644 --- a/test/eslint-plugin-next/no-head-import-in-document.unit.test.js +++ b/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-head-import-in-document') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-head-import-in-document' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-head-import-in-document', rule, { valid: [ { diff --git a/test/eslint-plugin-next/no-html-link-for-pages.unit.test.js b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts similarity index 94% rename from test/eslint-plugin-next/no-html-link-for-pages.unit.test.js rename to test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts index 6f292c9cfb..8a17ed983c 100644 --- a/test/eslint-plugin-next/no-html-link-for-pages.unit.test.js +++ b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts @@ -1,11 +1,11 @@ /* eslint-env jest */ -const rule = require('@next/eslint-plugin-next/lib/rules/no-html-link-for-pages') -const { Linter } = require('eslint') -const assert = require('assert') -const path = require('path') +import rule from '@next/eslint-plugin-next/lib/rules/no-html-link-for-pages' +import { Linter } from 'eslint' +import assert from 'assert' +import path from 'path' const linter = new Linter({ cwd: __dirname }) -const linterConfig = { +const linterConfig: any = { rules: { 'no-html-link-for-pages': [2, path.join(__dirname, 'custom-pages')], }, diff --git a/test/eslint-plugin-next/no-img-element.test.js b/test/unit/eslint-plugin-next/no-img-element.test.ts similarity index 85% rename from test/eslint-plugin-next/no-img-element.test.js rename to test/unit/eslint-plugin-next/no-img-element.test.ts index 19c905af7a..0c86d83467 100644 --- a/test/eslint-plugin-next/no-img-element.test.js +++ b/test/unit/eslint-plugin-next/no-img-element.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-img-element') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-img-element' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-img-element', rule, { valid: [ `import { Image } from 'next/image'; diff --git a/test/eslint-plugin-next/no-page-custom-font.unit.test.js b/test/unit/eslint-plugin-next/no-page-custom-font.test.ts similarity index 92% rename from test/eslint-plugin-next/no-page-custom-font.unit.test.js rename to test/unit/eslint-plugin-next/no-page-custom-font.test.ts index 6890246e4f..9887496c4f 100644 --- a/test/eslint-plugin-next/no-page-custom-font.unit.test.js +++ b/test/unit/eslint-plugin-next/no-page-custom-font.test.ts @@ -1,9 +1,8 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-page-custom-font') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-page-custom-font' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: 2018, sourceType: 'module', ecmaFeatures: { modules: true, @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-page-custom-font', rule, { valid: [ `import Document, { Html, Head } from "next/document"; diff --git a/test/eslint-plugin-next/no-script-in-document.test.js b/test/unit/eslint-plugin-next/no-script-in-document.test.ts similarity index 92% rename from test/eslint-plugin-next/no-script-in-document.test.js rename to test/unit/eslint-plugin-next/no-script-in-document.test.ts index 5547dc1a7e..5ae5df29f8 100644 --- a/test/eslint-plugin-next/no-script-in-document.test.js +++ b/test/unit/eslint-plugin-next/no-script-in-document.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-script-in-document') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-script-in-document' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-script-import-in-document', rule, { valid: [ { diff --git a/test/eslint-plugin-next/no-script-in-head.test.js b/test/unit/eslint-plugin-next/no-script-in-head.test.ts similarity index 82% rename from test/eslint-plugin-next/no-script-in-head.test.js rename to test/unit/eslint-plugin-next/no-script-in-head.test.ts index 425571388c..0b750d5ed9 100644 --- a/test/eslint-plugin-next/no-script-in-head.test.js +++ b/test/unit/eslint-plugin-next/no-script-in-head.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-script-in-head.js') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-script-in-head' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-script-in-head', rule, { valid: [ `import Script from "next/script"; diff --git a/test/eslint-plugin-next/no-sync-scripts.unit.test.js b/test/unit/eslint-plugin-next/no-sync-scripts.test.ts similarity index 90% rename from test/eslint-plugin-next/no-sync-scripts.unit.test.js rename to test/unit/eslint-plugin-next/no-sync-scripts.test.ts index 934b89b311..9d402c3a13 100644 --- a/test/eslint-plugin-next/no-sync-scripts.unit.test.js +++ b/test/unit/eslint-plugin-next/no-sync-scripts.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-sync-scripts') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-sync-scripts' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('sync-scripts', rule, { valid: [ `import {Head} from 'next/document'; diff --git a/test/eslint-plugin-next/no-title-in-document-head.unit.test.js b/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts similarity index 85% rename from test/eslint-plugin-next/no-title-in-document-head.unit.test.js rename to test/unit/eslint-plugin-next/no-title-in-document-head.test.ts index b20f5fa358..e05bf21b71 100644 --- a/test/eslint-plugin-next/no-title-in-document-head.unit.test.js +++ b/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts @@ -1,7 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-title-in-document-head') -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-title-in-document-head' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -11,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('no-title-in-document-head', rule, { valid: [ `import Head from "next/head"; diff --git a/test/eslint-plugin-next/no-typos.test.js b/test/unit/eslint-plugin-next/no-typos.test.ts similarity index 94% rename from test/eslint-plugin-next/no-typos.test.js rename to test/unit/eslint-plugin-next/no-typos.test.ts index d461cb1c61..ee8a26b231 100644 --- a/test/eslint-plugin-next/no-typos.test.js +++ b/test/unit/eslint-plugin-next/no-typos.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-typos') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-typos' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -13,7 +11,8 @@ RuleTester.setDefaultConfig({ }, }) -var ruleTester = new RuleTester() +const ruleTester = new RuleTester() + ruleTester.run('no-typos', rule, { valid: [ ` diff --git a/test/eslint-plugin-next/no-unwanted-polyfillio.unit.test.js b/test/unit/eslint-plugin-next/no-unwanted-polyfillio.test.ts similarity index 91% rename from test/eslint-plugin-next/no-unwanted-polyfillio.unit.test.js rename to test/unit/eslint-plugin-next/no-unwanted-polyfillio.test.ts index 446c8d4534..f8c57f42bb 100644 --- a/test/eslint-plugin-next/no-unwanted-polyfillio.unit.test.js +++ b/test/unit/eslint-plugin-next/no-unwanted-polyfillio.test.ts @@ -1,8 +1,6 @@ -const rule = require('@next/eslint-plugin-next/lib/rules/no-unwanted-polyfillio') - -const RuleTester = require('eslint').RuleTester - -RuleTester.setDefaultConfig({ +import rule from '@next/eslint-plugin-next/lib/rules/no-unwanted-polyfillio' +import { RuleTester } from 'eslint' +;(RuleTester as any).setDefaultConfig({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -12,8 +10,8 @@ RuleTester.setDefaultConfig({ }, }, }) +const ruleTester = new RuleTester() -var ruleTester = new RuleTester() ruleTester.run('unwanted-polyfillsio', rule, { valid: [ `import {Head} from 'next/document'; diff --git a/test/unit/find-config.unit.test.js b/test/unit/find-config.test.ts similarity index 100% rename from test/unit/find-config.unit.test.js rename to test/unit/find-config.test.ts diff --git a/test/unit/find-page-file.unit.test.js b/test/unit/find-page-file.test.ts similarity index 93% rename from test/unit/find-page-file.unit.test.js rename to test/unit/find-page-file.test.ts index 7664b1eae4..7520c03f25 100644 --- a/test/unit/find-page-file.unit.test.js +++ b/test/unit/find-page-file.test.ts @@ -4,7 +4,7 @@ import { normalizePagePath } from 'next/dist/server/normalize-page-path' import { join } from 'path' -const resolveDataDir = join(__dirname, '..', 'isolated', '_resolvedata') +const resolveDataDir = join(__dirname, 'isolated', '_resolvedata') const dirWithPages = join(resolveDataDir, 'readdir', 'pages') describe('findPageFile', () => { diff --git a/test/unit/get-node-options-without-inspect.unit.test.js b/test/unit/get-node-options-without-inspect.test.ts similarity index 100% rename from test/unit/get-node-options-without-inspect.unit.test.js rename to test/unit/get-node-options-without-inspect.test.ts diff --git a/test/unit/getDisplayName.unit.test.js b/test/unit/getDisplayName.test.ts similarity index 93% rename from test/unit/getDisplayName.unit.test.js rename to test/unit/getDisplayName.test.ts index 974d0e3001..8906220979 100644 --- a/test/unit/getDisplayName.unit.test.js +++ b/test/unit/getDisplayName.test.ts @@ -25,6 +25,6 @@ describe('getDisplayName', () => { expect(getDisplayName(ComponentTwo)).toBe('CustomDisplayName') expect(getDisplayName(FunctionalComponent)).toBe('FunctionalComponent') expect(getDisplayName(() => null)).toBe('Unknown') - expect(getDisplayName('div')).toBe('div') + expect(getDisplayName('div' as any)).toBe('div') }) }) diff --git a/test/unit/htmlescape.unit.test.js b/test/unit/htmlescape.test.ts similarity index 100% rename from test/unit/htmlescape.unit.test.js rename to test/unit/htmlescape.test.ts diff --git a/test/integration/image-optimizer/test/detect-content-type.unit.test.js b/test/unit/image-optimizer/detect-content-type.test.ts similarity index 64% rename from test/integration/image-optimizer/test/detect-content-type.unit.test.js rename to test/unit/image-optimizer/detect-content-type.test.ts index bc2df8ba16..b94d613fbb 100644 --- a/test/integration/image-optimizer/test/detect-content-type.unit.test.js +++ b/test/unit/image-optimizer/detect-content-type.test.ts @@ -1,5 +1,5 @@ /* eslint-env jest */ -import { detectContentType } from '../../../../packages/next/dist/server/image-optimizer.js' +import { detectContentType } from 'next/dist/server/image-optimizer' import { readFile } from 'fs-extra' import { join } from 'path' @@ -7,19 +7,19 @@ const getImage = (filepath) => readFile(join(__dirname, filepath)) describe('detectContentType', () => { it('should return jpg', async () => { - const buffer = await getImage('../app/public/test.jpg') + const buffer = await getImage('./images/test.jpg') expect(detectContentType(buffer)).toBe('image/jpeg') }) it('should return png', async () => { - const buffer = await getImage('../app/public/test.png') + const buffer = await getImage('./images/test.png') expect(detectContentType(buffer)).toBe('image/png') }) it('should return webp', async () => { - const buffer = await getImage('../app/public/animated.webp') + const buffer = await getImage('./images/animated.webp') expect(detectContentType(buffer)).toBe('image/webp') }) it('should return svg', async () => { - const buffer = await getImage('../app/public/test.svg') + const buffer = await getImage('./images/test.svg') expect(detectContentType(buffer)).toBe('image/svg+xml') }) }) diff --git a/test/integration/image-optimizer/test/get-max-age.unit.test.js b/test/unit/image-optimizer/get-max-age.test.ts similarity index 94% rename from test/integration/image-optimizer/test/get-max-age.unit.test.js rename to test/unit/image-optimizer/get-max-age.test.ts index 36df6a8468..10fc8caff2 100644 --- a/test/integration/image-optimizer/test/get-max-age.unit.test.js +++ b/test/unit/image-optimizer/get-max-age.test.ts @@ -1,5 +1,5 @@ /* eslint-env jest */ -import { getMaxAge } from '../../../../packages/next/dist/server/image-optimizer.js' +import { getMaxAge } from 'next/dist/server/image-optimizer' describe('getMaxAge', () => { it('should return 0 when no cache-control provided', () => { diff --git a/test/unit/image-optimizer/images/animated.webp b/test/unit/image-optimizer/images/animated.webp new file mode 100644 index 0000000000000000000000000000000000000000..7a1d3fe146ae49b89f0cf8ff33864c3053562960 GIT binary patch literal 37342 zcmZ_01#BHL(=L2+!pzLf%*@Pb8fI>oISrjKGc#ku4L8ixFf&7g4JYUJeLsD=SNip@ zyp}v#k7ciR{LC}s)sUBwSxy1~w527~wAA=?5C8xG#=koO;y*=PMP3=^U+dom2K;L& z%ZOn8PxF7DkO2UI|N1FW|C6&O^qT`@4=da1EPV=u-duk2L-*nfSKfFP;-H`I&5Ui4 zLl3q&P>$MEbgVeoZ&cp}pIq<#$?m`rr&z+ zhwk{LM(~3mbrNND7*KFhJTQ`vn{s*wV5n>tRh6X;bah0(MrE@z6Tz`dIi%Dh{SZG- zMbD^GIIk#Q%T*^JXd3x80gs{grqq3xczidLQ$;m?oK87Zw~=mfKM^X7z_rNjrz25f z4H3nTCeYlnXz4z_PA`zx5daIC5p?1g{~?lVT}F18TxWiw(Yn7UWV?V8r;HCs~UVtUY7Fr(hIIcyxtR67Wp@^cVKp9)(@ zYVK6hL9PMKBWb$!en%Q{huh>4m}iEPEAS)u1#wBqmx=5jymjrIe9zZTUnq}={QQzg zC2vnSEmMoihf)1UmkFm&4wdbfmwrH|uqjoAnRyMW!U3#Ugc8Q_j8>}m5dpeI;DBlh0MuIY7VGkXZ$Gx1B!+~^e+_1fM+xw?4w{2__YSxY>S zNVmhvE0v+)*7ehi*3;Kc>N9HcAlnvY4>#UK`b~7Wusho8G=!I zm4+gK+b#(_Jfx+B7zIFbG-<@Em@kFrP@YLl-HaftQNXQ2Mb==2XuKyLZ!`;VfT^(+x`x&We{GZgNW5ajn9+JJ5M&0|yKLzV-ghvkNZ|%D?HOdGPFhejiLECeB~c zgI7CgDO<~1Xs60^WCkax53Q&(P>zMM8Ex5b;bvD868mBdyIOpC5~KXJzJhq4DRX4h zt>UGr(o&*djjr$Uo?pz9K0Tf)nsUcOR^VHL7B=Co#xxQ0s5(o;el8>-sH9rltuhh9 zQ+YMcsH#_60Fz|4Pb;HWWKTWK&`yzL-Uu2$2>exI3+;`?0 z+u*Frr&bId)NepYa6e2fVK0z+jv(bt<`q-VR)~FwCOi%iQ<5MQ&(KsZp(Ku+&_K93 zv*zqc^h7!y}E9SdAPU2XG zLsT;d*0-h%8DAv+-73a_Q94_F=70aERz_c~i+POlQctApmU+C+F!q5v#OzeW5jHJjX*@~?BSS7AfR=LfLT>sj7 zzOcutE5Uf0rnD*r&B_%;GDahSK`4CLEm<)D2s4i%BK5VOBc_67a|!8YF;IkQHR*+> zd<+={2U3WwcDn;Iu&!|&p;8PIB&VW^ORf3+ieQd2cH>*hO;99R3c=P0di-PGFK$jj z@^VY2#}#7a49j4$zr%H z2Nyemp4<6yHqtW&9hwHWBbe_*SEQzP1Bt6)Cm1B47*urU^hb_Xb8P|{jN-tD-wzk7 zpU{a#!*4vFPP_sm7K?zw6@_5YA0y+mvfDlDEi&~py~6*HPm@n5envin8s!i@-B=a4 zWb&y@HH(*#A1Bx?QP}>W?@l;h|HHTCgv$<35n&YtgOBthUa_@Hr^jBf`%AR3zOMaI z&;V-PdS^?h6ly8XuSPA;lLi5U5T!#oER8711! zj=9%*)JW^ZbNd4-W3ZEeZJ|({jh+H6j{_e+I`q5jqng6?&k(Lug2CGlhi6Z?fyr6LXvp-+}Ay56&W8J;#1NS;G!2GTcJUB=Q8Y=%{ z1-618Oaif9-wmU;KhB)z%OH#4smAlLzN#Y*78pLPx6ZNN29O@Uaa`}hdFl(WnI*$N z%MqrPpyp;HM>Cz4vxq#vb)`#Iy+2pC`WLdkH#K#iM{)AXO?Ex_eBydu<9IIHenw|B zJ4CmhOeLrdA|FrYMFaz@B;x#OjD{mxJ%(L2n5ORUQVNy&!% z%%h~}3py}%Ad5*le1>-OPbroak;VKA9rmTcHh|Wf&M@=VyL%0SSZaIW&$6!+|8~re zyra{{c=i7Duu(?>o$cmMP&hky8V*;}4~5=!;{^nt9)nOMI!fQnsC9=|Qsa1Nj_fK? z%BN8UffbZ?MpPhxQc#kQ9yb}m^J35*|4{YLrmihA%}42ZwueKP&RY9*;8)id;6}Ie z>A?0DRi+n{v$@l7|8vZXB!(v}`Vv|F)71Uc?BmYi!MD(@H|-o$`nqWg%eiU{$T zt#K6QBkZ?gOt?2_>oUQnD-M1G(mQ^QqMgqA>UU=@YE_N&$_}>I=!GjgS+BzB8YKMD zzJ?rI_kP{8ML{s!cOn1Pth!0t4_(y4down}jp-IiwqhZO#08J9btix`7b*WkX}j*@ zlT55b7=D^~a{!SMp%A2Jd-Zb4XzF5a14h`=RGcF|Iz1&j_C+yh1r}08d*D|W<)r$Sug>$#YVuOsefeT)H;EU!t zML}q-l3ks4yg`xldvY0KRm7^q+Ln@9--w$_Aj;A7DcGwS9>Xw{7*VTwhM*X{VWCnX z)Nmt+V7IW2KtP5#YoL-g^nkk0r@PiQF<=`d{^*H0t{m-WLMdq}>M;34v!}QgbbjC4 zmO43jZk8y`w~W~JUMex$7jMD_dGwB+c;s2@mD;Z~MHnp>doq`8L*IxwL1@~vb?2sP?YzolGW=-VWSyCS}v-Tpc1>00)L zg(e}H7lYji8^61esP$c9xz8({L@V+S3dA(0P4CMa*Q2#lODjwLd|s3qnGwejwZ%h= zl~Uf$#dF|qK!pZys_LBWw#VO?NG1pFp9okWl+r=!d3(EA zKMMF!7*QGpnR;HiwM9_XhajLu1<^5IY->7gO|W6}|}4==6Ma{pM( zC2_MH_*JemA8rA4Dv0st|tmu z79RU`@V&1E*8;(<<2^Ikp5nN^_?r?(=6y{$1<-PQxXD0OMJTE1mzU%{<_sf^JDqi@ zdywT{CZgi2Mdt8B4jA^(X7){vj!Me3E?9dsLe2~5d9oSnP~_@417|b!`q3+=J|*(h z^!v$u6dl(#9ZB5)X5MGL*TcTe!e!?(^b;BM(7YaQlhlM9nV(NYXEW{lI4bGk>;dCK zj2PS`^kKKT zV7T2wu`H=)H!Di%x0>cPnQLa1XG%Evww-9oXkQt0dXKJ=;qU%j9)N@Peyk$$n2Olz zvKumT7{eZ8WTg!}&=|$E0dTWlfploPYYy#Hu2NNB_*fW@RSFZic&Z{g89At8)w&Xh z`UTMP1cHOGwK>Pylku$TL6}Bm#bc!B-FD#-z8%+3DFa+OkMzIIy-N9yh&(mt=y9vm z4jX?eLeUee#jw^3-?67KDWSeieV5R|EBL#5&uJ@J2b#~K$$(w(i$8*9&V0+4Y%fHb z`Rk%s(RR>Aw<_9~;4ZL5;%`xWsRdIzT9`81SGZ}e_DJkix&;5b%z2=M3)}Kxi;p>Ex#I|q{za=Stk!K|frO^j^FjVp%GXW7F3G*S-ywWU7ZRc#P zL$TaO*%+{Bo61IMnQ9WuSZcg(Goef0l*=Aa$MXoVdyHB4yvH$b*g4tsH-(4xP>5?i zyLLSt^T|{&IPS|#;&<&jqBft6#s;1r`$N7=V?X`jQsd>&;b|9dDnCs{$E&H#YG|_6 z{eY+-b>u}YG7()UIj8fI_g%q;LDmc{hP0)JVKykIPn{2)J4w;d3PfAU+eTfTvY)NO z8tMLvQSQ(pS4((v_fnSK>q3Cn@bkKXYFl42Gx1?;3O7|sT%!#sjbOp~#@1ROcQ5X! z>a5*;Eo3J%=6!J@U=|(gl6Jx^`|7+{dZKcDi41zQn@4kcOXstbeSbVj`&&`!5^4ub z^|z~|UNBq`*VFRld2WE-9?YhZTT5D>+fY!Cb##xBl@IBw+Ec4)^hN!Qa)LRpJx=D4 zx8qfJ6C0&>m7heFe4&ZxNP@{i%;Dl6mxdbgBOr3LiN$hQ2k{+4+~20x&7qACQ71H- z90`Wq2}aKX!L_&#DV}?_$v71JH9UER8oSBNf`7*s7dzr9V}6kRLtSbO*NQ29a** zk7z&x&umD3xYk!zNIwOYA^$#{J9fwGW)e=Dx6~h1W)pZ^yKn}7B`=T?bp>R!`?W22 zK;^D(k#YU>q(aJOTWs71oiC`aPyh5Cl>aHC$(ARGd9FDZ7hO)dt(I|B16oX|7S&i?~<=^xV*8 z{3K;s#eFK$j_k)qeuY9lZ@|nurlh+OMb_A=*k|EvOJ)k**w5zAQK6A;KQWlVU|vhb zKQu)&?t1-`e}~TM7P}D8rF$B7D~}wnEdXbn$qQ&kOd)Gf-n~06ir+F(M|?z`uFrEG z;53o0z|&MI6X)g?MWEjW$$mSfuR(Ro7uK8p_f5U7_>aP~G;Ygznn7M}`LqWrt(oWX zt3=pbin|u$jO5gY+5K`@(NmRTb1c*(SoUv2{RNfQ;%@qHAB-j$lGsCoWA- zBWSjnO)T^gorxTkW-Rd%P&lgDwN>QUayz!Jh66m^1WZa`_IB#rNvvcQi`llMxN_@i zrfVg08#BXWT)72Y++Q6bpF$D4PkQZiX^}8cxj`BY1(}Q^y9kJC1syajEI3Q&O}kx7 zj}VN+d@My=W$`J7b=JZxXW{kjx`7|`Saw>^M#vdFBYmiRTp^IXUSu|7a73(b`RGlA zWo*R8hvmQ!(F#xGA_+`Z7F1b=)@np6b45v9!7pK>;FTq9)z zJ7A~#z!UK2*X4*cOc_@Op0?LQuI~W%F{#^JbCEqi&lKC{My1y{*KW=l59LBdQDVNa zqP>u(-zp&+r1(N5Ve&g-#onFEwCYG{a6u}luxq4-p6VsI%)o_;I@)K-9{e;I< zZst#42cQdxvJH^4Jx0sZQA@&YI(!42WawtGU`nm@PajWp1m~6W0Pn-tzP~jwMi-I2 z|GX_C3n`9*%iBsKX(FRn?GSYs82m1pZ;$2GKoGU4wGPJ@hgl*%`DL^JoHtrfCr%Zg z*lEfYvY5t}K0Dl}c>2Qt;apbzRZj_@)9HghJ;4kz2)V3_O@v&w9LOJ!&Se~1$aTa> zQ^CGNip-@>twaU4XF~}ZxQA9#>saI8+SuFqc87b+K$ib%2e+Adbipy2{m>wTGlA9- zCzDFryTyqzr(}~T1!t!DZ}hFnabkn|4q9ap_xIIQ*R_V6ahmj&owxG?)SJ)T90Yjf z7j*Z9FA#n|pf%b#Ct*jk2k4&2<*xM4mp6aP;-hr}DV&`+F^cbM&7rm}Ub6JO|NfjKT_Xsv%}>1vE67Rw-Tbf zQLGl%D%h_iQ9hsfdIy?B*7BtSM|vJj9%Kdn%OW~L|9@CSz<*f8um9x#VG+?}2WS9& zRBrvEjzH%ZSwextWT2F@mvT{q!-k9}&nvjcL*H&AduZo6p(~@RS&U~K0K-JZ&Da2q zIH%s#HT7$b%XIpXcorPG&*=__E)fC|b#Va|4!{dZBC~)BK{F+@Wct!irrisjvA%4F zB)P{=&==k**qj350+@FvX-HWmwWU~`&ZedJG{#qRnj@2!t2r13*cYACLPJZR% zDN)Zz9Z%J@xqMz~QBOy_*B^`Cp}IQ+YbR${de{d}G=gtONUJgRx5drswT6qqi8{^?bxL^?6rq`Jj2sBcu8wkBJIyRHc z2t$$i9cd2aV7^X7X6MBQD|POnXgt>Mb$oq1TBXB-S^G=u8wC?E$e*ex&)FS}lEyx` zgAcij5`Fm(P|YT$J9X?k0C#!^wlM9XOU>86Fp&`&H5~aRlpYE!`JT$7`OXuzRXi{I z!vdNW+nJnDpx=vrUT*0~U=aeWc?su#H?qMANcs*pkKaZFQg;FKDML;~zx%`VcJ^#c z&S$J7{s~=%_J?WM>DZp~W$eSrG_Y2Ntf;sTC#do^=JT{?+{rnnecb-gZ%Nf8Q zAfY$)HCoX!{L`m5ooH@H$g8456BvHCZ&PU=Z=+G^3;TCB)Y#|(&U1)`^1F2GJsZsa z3juYcI)KBX?3{SfMJKE+b(W>2%>THE`G^zN;p}dqv80#ytJORq_W6PX13WJr)`>e_ z8ldTQ=r^$o0)DLMN}KJ3J^Z?2^){w#r1NSN(v|}!$4#A^ohb>~k7IbOtuuKhbviN9 z;3s&DWE~WE+#^A|g{iJyrN#w55qYVFD@-%xk0vo>`^uswcvFMWWSLI>^<}RtND%CsK;s|^U==# zZ-U+Pi{<)ZRtEf~$C5N~X4mpKHBL1UO@WSEQ0U}Wy5#T)&SS#D`5sK2-I8!fx}^O7 z#BPTEf2?lJ|5{zveY$^EHyiO!J%o21z$s)dSg*8jNZQ%!TYrNCm9%cS-}$dKum82Y zw0VeXf|~X~Vfa$A;!8FD2oI4b*^(lOx#*KAD+1`Y{L+ZMaxR=r>0o~P3+DdDD=m6fV z;i9__3Ep}MF5BDWdR#Dx?=_n49Y6?Xex^Bc{Y^W=zA4`I0SUMqi15(*`?4acwj}UA zH2~+1dDv9NUYeF*sGu!FB#9RXcfoe>Tgu9mnk&G3j=b+y=+_h`c#JQ0+-k)m7+C(B zM0{JVy1PyXJ4MipsMa9{NhFP-IR zqL%8y-;f-&Xt!~a<-f+YDG1xIQxsQjp}|x`2ZMv6eQky}Q4$5g@xP($UcAT|9^m@$ zp5u<&#zmzvb+f}M-hbaN*QoCDY_B&W7?G11TiKM(){qi8IXyrC9_;{ZYZ~wDRKx?< zxGNjVYn0QOE#pV1xtxf$R5z?^%27r?H)_D-{vD4wgMRHCe|eMd z-8+)~=yW&@qO!^2WGIoqgr6&427PuaL)iTDx9M9G7Lqo1)SrZe4JOQGCByjd%>F#0 zb5fd818L;b8$zc{3%Ff|EmXb;YNgFknjrtUAOLomSu>j@K;l>UWnq&3$r{JB@-Mk1 zMjL4x#gR}=-fDSEN{!;vZ4tt$Y-NjQ_e^izA8xDLO24DRXhP+F>;TCK5VMN}OPvlx z_*vbB;P2Q-A)uhdB=c-`5c}y%)xRYTVaf&d5LoT>osnE0A$%h$7zc=1>bqoPG#9@< z-VXOCS63G{ra~)pjUeoe#PS17uJcP>ZQfRJA%Mzx8@8sw=NCI7mbdS|DBq$CvE+0M zTNu}b{&tu=rv4j@fP}I)A`VCz1zMwxikg^rJD%~x2v*>m!R1;wCOy_0mDx`B{WYoX zk$!T)06({gt*rTxUJFHFK>BW#4^3{vQ*f%OD^~dU7ibRV00ctGS)rs+Gb=E@gRY6( z6MpXcKdE_+`N>j#2BVJ>o_-npBxmpwQO&x#bsbqOBmqX`vfl5@wJu^StW*XROR*xe z#yJan(@bW5wJ)qJwT5QU{X{Gh+z!t3ZM>QlEWA3<`6;#Q&S@CFJ$HVIh5uUDi|# z1{4}tpO{`EnQe*3ZT;3gcXB4k@r2$p&QU8#Ma5J8we0EEkUsobOI& zhCWQ29z&A#0V4$%TL}-kdzmzoS5Ym0d|sPUM+I&)f1i?XMlGVo4Tc;~7I@U=mH}A8%la)|WTiY0C)}~=9>p|tjDKb`g zH)^fZpk#SNmnsp%kF_6;QAfkD;WWqM3-sf4p9E7D2L8hxRg1slg<;%&Z~I$ZL6; zX|E?~F-@SigZ&D@n$#Za>Zt$0<7>8?3Y%-m8GN{j0CJx;)u&8$X}Ez}wh~_!*2$30 zRF)f3oewk=>QZH`BXsYO_{fsEO6s6)8A1+3_{aBdhY--nf%G)b0%3xW> z>L1TGzlg&J}jS*j+&VuxsTT)W#uhCAod482`LLHL|^dKj9SckKo1PQy3&;b z6H*>PpvM2WKcDiEaFoIotmTsO@lj<2iTVJAbDCO z&v4(AyX9a50SGHo!>nMX%nGt_poTk=s!t7-OYs$>A%<9bb{+1LDukmX6ZO}MewdI? z-2|%y5AXQk*gY!*&V-NMM&P`&D@Vo{_+!j$Ddjkc+o@ZSEzNa>F#*1~fJZ~KjkBfM z6?)&%K@g(XZ>eFhzV?eLlbCw4G0JE%;hgon(_V`pa^-N2LZ*4?b3@trnh zte1MaIBwR?aMQk*_*BUl74`9PpD3uCt>i9|jC`Q*%rfO=M`AF7`$Q%hMNF>rQTSOA_ zJHL72X*3&Sn@sdISqK>aLhb-urXf-N^_RCZIgX5sX~{8(WdSxe8I;yW={1w|sWW)) z)RX^yX-+_<9IpsA&rb?N64RC}3ndQZ%@UdV4wy~Dmw*+y+?L^T)a@h;_gJ(MI9d#R z4q%ibMCQ~8Nqigxo!Tf_ImB)$V;U486&pQ`83ucB*LmHh>EJHU;v?V$wM+aE&od>P z$~H8Tw5LiE-X{lXY7|(ng#Vu9NV>)TX+gLR5Zg)NjdD2Ob!EDYk zHNJc5OE)fzN73nBTi6%|Q!^L&OuCnp8s-7GG7G{XoQAF)gtow}b);X`L}MrFgwT2I zr{}i4BQA@y)zNOyl8Ggj_|ke(*(`raF^1Jr)uFH9K>)iq6_;gFjwOtL|0~)oK7Ve{ z53|vhjd_HxdNRzN2m&|4OPnWL7PS)PQY=?J|st?l_YF0}U5R zO*1$wv2w-mR`#Wxx?Bq3koyqZ2(+z@DxPV$`|7Zd1ATkd|HoS+|HTBA9j*gUb)5X! zZ49S2oR*;WHohV?j~~23f3@*bmLX(2B1zC)q^|EE+#@TvVIC0FY(jf*DF13cZ{8hz z^NceOJm7%b>gh=|q`g+=FoJ0MIbS{+jPhWy@QXHi-l2g8&``Is%Kg=0&)53VU+R72 zuYZoZu<7~GvG;&olr=KMI<>#t45Y1Zmfd&fH4Qzm%}C5J_@> zE~A-{ov2mVEo_Q9RZsn+3q5&^%x6n={DOz6kKQ-c;uCal;TqV3IuA&UiNTB#tHvo`k)HERd>2rL+jvy9_Im1bB4QtLaCO<$uh~^ze0M22 zFu3rx%A6(px|)N5c8_o$T6*#eV8SMj9~klHiF(JA-ujnt_m7*jkx>Mht~TZP>_nu) z0LNgZ0Zvr2+Te1*seZcekwy<4^nnGLSF(dQa}L_&4L6?zmN_nF{8kMrP@$))urhsC z3<+-N`C@zSrMuHj+hQU|gD{Dtb61#mVX%?q-a$d^iG^!dIu+kmTt=%$s=C<+gbQ?E zWX*d`JJ?1`2u=eaQD-6+s?N7TEc+^EF}aah2=Ib8_ZC1?nF6Jb!Q@d}RHj|V0K^8j zL-sj7iO0};DOO432WCR?^f+u_7!gJ~EoS+Q(!qzA|6ULihep$2S=Q_JiokVNZ_;+5 z++-%K#!#{KPaTbPmkEJm@p|;asaLz>GfKdfR;dlVKlPpa4p&*d6skrHK_4vPVL6P| z*4kb%v=3P+XLvmKrLxDDbnIpdQz3?eABPl_B31rV%6E1XzPi~=*_V}qhusiC0~aEI z?5I$XF-J+1OW9;n#aGXB$TRg^iOw4lx?}RMRjr>jgzQ0^rr%;q!4-ZB+NL3l#3#(?cF~vW<^$VL8Y9g}Nk_)gso}xb4D&s$&)KZF4D&ijhd&`!^6`T9 zNea_S4LHW^Hf>q_jh~6L#^xdpR*m5;;QJucz0*I%U~YS8D5;P^YYX_$no7lEynw_N zT&c_oZ5JMND}AgKE(bsHH>DJj23vuXA*p`ZW0992&V(G)hF~L?8OnYbmWA5>pEm)3 zZ^OnoJqg={Jbn!!#46!!?T_d=R5NTIDQQ5)&eVa-=+H6Xg)EZArlg#G(!=!focQ;S zV~c%&-pd2|*HhcsO2)#j#LW%u!eK@_*K?CFep{XaW+G{AP$o^dTEjdnUEdHUm*dND zUi(}O`Sj_cm5sBCdMx6Rkn5oblwvE~ic4oehE|;xE{uw55w!GFLo}va3;7&>fNgcU zTco365!DxNmHIdJd&YFFVtUR`D1=r5EF&h>awS!p6|TKu$aTOVVP`8=7YE?cM)z_8 zXqE|1cmdM^$$t50Mu|xqEcUYANEW}6vo=cv@#yY3mVTW*vecy`eH&UrHB}c`w^$+y zt_=-)0srgAkL0Yzqn3wr&-RXR6=zCbMt2~e7K;|kE^}=W8gwddIs!KVQ%$Nt!3LTS zE?mKnFI*4WqXUHB1bQRwK_kd~+tBm5SEjR}BdAgBriY^j;?r~(23cet@@Oz$PPE8% z7lFWR(qilI!uTBylFvurN}@67!Cc(m}GQ<(3Cq1FXBi z-Y$K;DsdKa!68gN-5>*razz#Lg<%O6@+&h5@`%aLmh5-wh$%DIaWnuOsst)5E}joP z>gPCcmjG9LC=vWji>Nk^F&v&diDwchX4@Y#z?~`S{0o|l$&J8rTCs*S*%J>RRqP7F zUBkILT_K=f&na*t*^C2BdJks*SH-G}e7?+LyU>$@4H1@5eX_8DE#n+bNsr}| zsE1*P@YSSuTm(+NXGYJ({+F2Aq9ExPo0PA!)CITYIp73ZA@6&5x!Goa`^~SjmY<>= zFuE;@#D&V~ZgDMlS5r2{Sph<|Mg2;Aprl6U!wR=&g%Nl zFA3Z)Z*!o1J)?F_6({|>3qjxB2aj<2?aT0?`v1f36K=Fs3yD4jcu_YooPvOnHltM_ zipqX!8n;Za^z*wYGs!I;Rj3&R`K@2X5dg7~4rW>$DH$3jUFNT}`(sBAYv&pVm5__tL+nF*mv5aaKV++oE}8?hOLeCrT(Ci)Q=zF|@-y^Z|J z-?;9D&>9&YUQd?GhHl`W%~GH5N$`fJQV+&BRBJ99mzqaZr-lF^JlfPP=zX&XRKRPmbzywv+7lPp zvDb??jC<7QK(*c}Vt3eabaf5iG~*=_xGPH>CV6%zN`CH{te$V9%GxBG4(PH8mD2qdzFegQ&pRvetCs|d? z#AWbB;i$CcYJ^~v=VD752JQW^GZ)?Qi!lC-pAdwQP)`U%!W({K(NT*V(Q+Fp>x2(C zq$Sr+pIjx8)yv#a&_aAp9KB;iHMM+rO|BV&~SKCQy?Q zJBuNzD6E8$=>1N~fpuP>*t=K6UHeG5>vYjgjF6X^UyMs9h(AOjRRg-@kYTsCN&+PX z7htIrGroPKRxSDHxp0}^(jZk2w-u;%M)Y~{;^){R%Pe?PAVmzVA9W6mtqpN-YAbv^ zLtO^pTa#~ejujG=_^TnRt>*eqb{cD;N2j09tR9Iq1?g&mjz^v7ZCd!^zil*3Z+Lg| zrRy;XI8dx?-gCCDHe(<1e<#ni*=GlC#c^12oKrYK>3^Qd^TV6*;(H|8z4!W{vrJ`3 zrCv%_1xxj3=ZA$J*in9$$7x&jc-oaFoj zz^O)w03_p?PW(gqP6b1_hT197CK3Yf0yf5J7+ z!%abg6R2FQCkJ>vKCeHbuPkvs7Vag#2}`f;5RUB-h8@ef@E23f#29;S)1_}l&^Sg-dZWAS6QfERodZfVC-x$O#Ue?^$n zSBT;IEsHFDCNSNX<#NM)SkRm+NkA$~&47;0!lbi`$CezCO|dUA-Wl889MCq}8v09GtI-6O@Zs9O!f7+Rd1*&hj5f||EeK`PkzOnRy6QHwt?9q)wC8Pf?jix})IHs-_i1nqeSBa`I-Y4Kq;cDrO zw|t{Ft?4ugHTgOMUo=6=(L4+zTi&kugA+~})Y@botqxm44~EL*R!P#AE>-4CpN$is zW^qX_`!^>QO^&Z{lX?*LZW80A+WbXKOPB}g*43u*rBw}P^^53^KtA&XDfZUwvfkA{ zo|#LgikfV;;EIoeHWCy|LR{(30(twlMS40qLQhJpFVy4f6)IsxW7pCv-@e8N=8Go< zHV+g(2Ci%Ir(S`XP(j8J2(Qud9n2!wFZ#kYM*<(2IJLs2|J`eGkO6>y1mM5&Z=((P zzZ~G_e>lJ>abq;q|8jsG*U$Z1M+rby02qp#%qO3#?|%;B5RG5;UWs0Jp#uQy^<7{s7pIksI2ZcgT1_zKv`xj21 zbG>BMp$lUvemQP^`)^V-t9wIp!0__9(;klDfFqMDc4zhQS>CIvl8 z>%=s_{)HNemAbId3)3EW=_Ixk-8M|{Xv7KS)Uy=TlM5Fh_*!b87w&RnB&%zuN>0Zo zYJi1o%3Gwf#>uO-PD^TrKnf+i&k8v2~kY&PdHn@VZ_^w?+{GL|sSAYdxS7@%!D zgTX;B>qLCciE&Ywlcp$b9`UOG^_moLDktaL!90^K<)5uJ~7WG&Xo}1o=*ms%nhzl%+BL!t@ zFLw2)r9r9I@*CDAOPmK4k3u9(K!v!)ojtd2vi78(A;0<+llH0Vbt)y z8O}b)=?k_w`*^`{A>f$LHBPp|MR0MNrU)0x{zy?b7g|Nr4cxvcfS|J(V&vjG=Tlbf zXGBOy@1kJ4cnU5z`K^iqm`1C}thWgx?w$7bRNno85fklHR{Yz`6PZGdz3E#6to?%} z$t;zbeYP_ilQ%^}73Ia8ZA%44SdUI`bWdj04>IbOvphXH#Hx0h-udpsk5Dga@SjfwxT59Nn3}!CuQhK!RkPxEnYZY};7lor2Of9qpK(2SQA|DKa_Dy~^0Vpf`_h_W^k11IA*0AhE=@+Pdo{d;2waH!e| zoR{(!ilw6PK(Q3g zZuSvC{9L~II^Ux{vg(zwK+|PebjO+$3JD{`ERQ)BtkPP7$?kWmiix|yNvVdbnVx() zM}EIb?DHOG9;zT{IMM?5CG^8fo3nB^x1ZF)qW4P9$Pk{1w|>X*jC0G$0>l0pqX~pZ ztSVE!fEm*_X!RQ{OlsU=BGkZ-5Pw)WxZmkP#h8tNtIJTeh{L8yFU1#B7x)_uoZe#B z9{sdTg8sdzS-{2U{utBCjB-tk$``p%G`Y*uEJPYP>NDxh2N0{bY%6SmNA7<{ZM$E! zP&*tAkg*dsLT;n!E~)AxnJfRw5%;M=w?SW!0dU#AL8f#isv&9~Lpw9oFLM|cGfP+A zG>@VJ))K|#Sv(Q^(eMTc%I$q0A-OqFyQa}gQ1e}9Pm^kj|D;J-;t=G(=Adl;^cjj# z+aQokx8`WrvEeqT$Z{V%vrFD-hBeSpR4*Z4)e$G!+HiIpPQf-`zJ7{m8ywdsQNC%t z$opyClYUvVC4&oxQf3$jJ?b`64VC-wRuMQBJ=YRQm&ix1rQ`KyK$CuVwNTRoVuEy% zxHP*Ofq{!KBTZJ)Wrunw;s+iSbau)}-KU)RM%#_^p_0#i@ys|1bWm8;MmJ<0Yaz6vG$_C}m;%@w~ zxOGw3lK9|Pu-~!765Ww=20Z=V^y`bG6cbl}vZBWH^BL%68t{oi-@I&Z8?BEhIJ|W7 z-#O00`}`uV=j;|t5Gaayt6;fA&OOESoCR`3F0o~=^sSUEd7Mp_O)wl#&SWXZA{blN zsmG&vZd^?K^+ETti(Y97vRR}W;f z#Yk8V)!NidcqNe|!ITrLWW-`2{vGWTEG%4RZ`IBfAAdUx>P*e*4iErjuQy?q(Ax{i zTWARHV$pFHX%i2CWRk{}lco-ww_tAI7RA#4_L4*Y;v#> zavTa+qdu{{>x#tX#dI2+TBkD3-oD;7X7X9u#MbcvKhEVvb$Z%B0%YNTD>e&<`U0&?a$H#B z9^_>40E<7(<*dU!iM9GmJ-F|PL}FRo8z=~&EHXHJ5>;Qx(cx_qQgpCGg9oU-zB_^*oova9K3Ih# zg|ZJ-oajbjw7XBejC#($yP~f_yQv<^$KVJCaNhUp+dhIGW1HJMigLL=XxnBhQZ>Kr zv~2^4<+MR+X*)EzE}ct=9BUEKW5clo)miU|Tma@TA)y~8F!O;h#Th8r%B@)9tmFGy9#xM9c5(jiAJIy3JWTp0 zDJwLno7o3FZI^nZ8vfcr3;j8iA2qn^5XwhJYfDR--<8RNfvgk;l3@ zPc?y5f^{K(f^lQUU^qgWDAlSl4|Yu%p3_RnkK2aSYfFWx&EJZW5d}!A!%DSF1-|tT z+r&}Lba7vEKDGv-hMF02pIb^=p*&VHEXvGO8?$KJdWq?)3))`7a0zZ2rHN2Bff^UrgDnoeql%!_;dXe{?6!UHs3-~9$$`OeM zHnT!_>3`T%Xq1CWKTKVbQzSw`QI7k6n5tmm@iC9Pv9D0W;}?#h+|gc zF@`P3(x&6IF2n{i6@SpmH#W+9jZ9jc|J{}nNTF;#W;OCF5OYp3+Z&HWd^43xln~{< z&rybDkXV2VRLbu)N1qb#7o$_Cvr3(@$3?fw(xg5(7jK-(St2Z2JEA!Ls_ysfZ3)vm zG`(14ep72|H|TRLPwQqT%tn#fs%9~te@}|O7^VYIBHY;pNlcXs4Fl-lXPo5zn=l>MDy#|bC z$3rM=AcZ*o9hd@i_`7ITzR*gBg3;S=`>nBKf|3#TiQ;pS?HXeZ;!$a-N_J3>u*Mn6 z`|fZ;m7six5WjKEaEnv!8E9kw0;d4)kejF(#~|p`aMxZ3_{tK2d%zjqK8CXnz+|K4 zi)cF7ypgEjmBj?LVMM?fd3Cw?-ZSBv~6pDv27<`Y*uXB zM#Z*Ov2EM7ZB}gC6+0E3T5JD*JNw+uo42)hUd-0VczW;HN1g=bVkoe;y^ikQsey)@ zt^fS%Qref_-lwfAttA87+cXvB&BjFO{)WD5A}k`94hktEIIC}1nH1F--K3x2itPa+ z`Oxqp_f+=`bKs~VhD_k{`N&kE=peEP%eUFqRolI$rI4dE>CzTPP{(IHp#J~ zN{d%7W?~c`!^r0cJIRZKiQO>V++hy*BW;P}RPs|Hk-JG~*$#9bbMYfHKoUK+mK^9e zFYg6iMVOUrt0w4GdP;4AvHFFr7w1Ay(&*Bm=d4BUO1k!f`*r=oUnavd17(4&qBZh2 ziN(6+$uSrJ3I+fm9Uz_$`Y}+{YHPP?w&@ll8GuZc zWIQ2c_p;+Hr*QPsf}(kZC$XaTQR|z0PuDgS9GapOecn$yzGfwX%r4qZ&w3qe4vfUp zs4pihhl0tQ0ov}OoO_Yv%airY6PNRY2#SwH3O7dF8~v9`I(YrDf9fRhZ&GF>v)_bB zAgTFed!esZM_YYi3lh6ELYDa)$yW)^`pk0WvBZQ^05?M?VXOGwS}r9Ux4&X1&M`Xu|#t zeKqLV7}qKkKK!~(0f^$Q;fclv8OH}7rK+1d2m|wQF5bb^7BS;7fxZHYy$cRxu&=mh zHaX+k?F#~@Q7j3V$%RcH5%Gbm64)iz<>S?lY2FNH*lT;hR21wiE4ceJCwuU9zu{3S z0+T;#zh~$GE#D8CS1AI%9$MsR{86Ng{JBV3Ya~w(w4~R7!=`>G9pe&w15zeqvSDTK zSE&ap?K;5gcm*Zu-fR^_wjNsed{;1v2vYS!8$5z-&@9);BviE2hBP;r{g@Z>%>XTg z7MH9ijq)~Vx?kCXU}1x_RH7-YN<1bvbb$}bGEY{Yp`{_1C4m5v*k~^iW%|rLh@ftY z6jtQEodNtbd@*VRVcFn?#1zVM*24?){^!Si$riSXhGLr9aLjqNp$9Z3jOgJHdu;&5 zF2(Y3VnE;_v>OVY&O7bwDVnE{sI}jL)CbWr>EU|+5m8tyXO+1PU{11)8m+QI(&;ZP zos;ZPVs!pm;qWThPx`K#s))#z{M%RT;RxBTB1AB^4HwizYyaem24U+c<=mDjf z0{nUA0kKsR&^Rnyt3RXdNHfeaGEKb>qmrM85~o|NEv2zJTEDWZ)1@ZhB%=_1&R9ex zhIi`UHQCNi!4!jL)gYHUUKL8Ijo;l5z2nt=q%WIHV+*x~A_-hfC=?o*GfBxFFp!8G zU^xxU0q=HWD*{l31xdKNAx-`5L+#%B@5dSUC=*V9GMB+1`RMS`MmMYtwc#IlB`RKb z`Pkmv*8EA5HQP+j3mw&*Pe6Cj&TsO42ET-V+re1h2I=pKYoM~LunGF)?vqy`{R0pq zVj)73dzmL&(SCBd%+@zdTIoZrg`8lmgFc*%e`Tb~ro4OX?2AJvQ;&Hw3ZuL@_Vxw; ziJ-{#YW^WQp=%3)k-h8?9UB6v0&eg?F2G{~q|HXeIfA4_btJh~M~tXBlp|!GHF~og0!kT0vFaT2^tlkEX4az>Nt*b zz~NZ)Rc?1x_^WDP7A`^54l{H*tT@mLwCWT zck3Pg(KeZ_#y1g_B~*PBxtC{1qI*ayR7Uo>@J}C~@piTDnuBKs=Z1 zOnbZfW)n2`^dQ7UQ@<{Nj^_Cqyz~)Q zd$xKU;9)PyrhvSp)CUcM85kiA{5G+naK6ys1Xkdz$bVo_yN9JRtf~8gt<8TE`l7OG zzaHoO1zp_dG~aMlunl5)g_u`G-=r`-LG+yI(lOq;ff`m2|H@V7r~5soK4Vh}^vTp|pM(?ND&xX$|(ENXQeZo$PfA#dx=HEvKa(UBFI&M;MU)6ur3 zek^nqz;exoXSY+1HjPHuZn;#QqD~3ppY3MKe>RyUeqTMN@bx{UfGTzevw~{4tqFq- zwYvOk{IwrjvOlxJ`~%x}YGV-}?(%M@X;Y?5z0;>xgE6ykTl!aE%ykv8tnDLsD)=+{ z7V=;au4X9MDq0^s1T$?eye9?ks*@7EIG^?e(P0#W$>D$--GHYrkSme82(fIy#y-sHQ#SRWnRn~_2kD|2#lZj;3z@198T|ME{Zw^hC z3)nSMX_k}WRO+mo`fDog2|PezPzBs3j?vvu;y*K`a>7jalx%@3n%hlQkwHxbG)!2- zv(@!P`J8}>J7>2H4N2JjjbT(VP=P=0>0YftoFs-rC3TX{8W{G)(RZE6zc#_zi&eeB zKm+V1>ICuU5_EbMduVTLFTs4XIm}_Rb8een0v>%C#s0KM2qA}>nHt~}^f@j*1`Z$# zcY7w3j%;nfe*LB>4do8T3%@CiU#)5RJuL5vG10+|4*xpG^DI94Dv-2-j_?K{m6$(a zMk3e5&f3a`wGfZ?cyio&Q!s8F-}aYmD%Nx1-WMh{lq54YBgQpsolD9 zz=EgK%OdxB1A=+RKK#N&o)57I_0d=CaLXLKIrQ!LDqvRX|LqiH3EFgY(C)qMqUic8 zf?OI8HJ$q#M2P7SNvFkNl#tcx9xn<7IW~NaCZW?WPGGX);&csk8S9kM~ef8_QfcW0KyHc@%$(!2GAv`DJgOugKawtpmaJ^y3CNmi~k}4HU6*-#4vqBxb zg&ZOaR&A=r2CJuqIvLEKbUJ!nGgg@Qmyi8curEeBg3u zi)1p?XDwU~#Q6&jw>D!{rVdeLGz_^mob`F~?8vExGLyx3IRV>+j{5uG7pDGqgLd4L zHrOQ0HKM>E&`R+sW2@#r)+ikqMhFHA1;0%14KLD`D@15iNOm_?xy4AxqVWQT!DTI? zb%AFkDQe{m*nSbZs)6h(fPl)7L~5FWTP?>(N_-=8iab%sS7L=FWYkX%9ToZIBmW(^&mRCEBf~W zY#cy|#3IV6Mc^L1G|+9}eo}&qHzK+y0YwaD{eu+E-%{?cm#P~~f8V_@q@dv@?FED? z_+H(bM;mRW6--r>$DQ+W^72PGbPkd6m}O< zx|VMP%cLpo5`fN+lif{C%e&p=_=@tv!a*#FnCLzUsNqiZUSFc=Z_Ps;#0J(Rds5O+ zLbRW;3Is+1hp1FY<*}w17^Dh1l|Do@Qd6a{vQB%%yi*_TEkst{`Wu46EnliEfv1${$k^5Xcljiz9n$xhP+U5}cH7@sqc6z+s9N#=;cNa$ z+kZPh-~X#>8UDl9Lmmpn0w12!mR zfFKGqG&ZEhT>9jp!=-V-j&O;Wp3zIE+sdRiDT0LblW;pzdCf^Pn|7pqH#PMMp(KoA zApaZkpzCx>c0cQEz91AM`Tf;*ngw@@&k{iU{KNKSH=JJ$?jQ&VeQ z=&|$PehLIqsRTUhnH2wVc1^@?no&|l#lQ4G1rmqj?{$mCM5G+qOy*T z!@Xa@gBJUn+$xR}q@IR!$v1VMO=1!E{!W$WNk1Zd?q@3`s8HPP>0Dv#=Rs6!MWloY zqZTPRGMge5r?ZmCOL5c%m@sCKP7~zfAoUqSy1^U_%2g2<51L@j3h9O;tJbbF>IPT2 zJI1j&{oL?YYN&GxEg=8~ZXm`hgltWGpS&q-g{=H-;gdo_Json!xoIOQ<@^?W(J$<( zbL}+>(4bG45g^t@#&G8Ug>n%68<(L^GLTfV) zFO-bpC!i`gWC}{jv{$E-mJY$lSPf4WVaRa9Mif99xDoXpd^OhFqQN3XMulgPr5ozW z&YRwT)er~zy4lvnBHjnqZ)rl%10a4GL-gq>bj^{3UXql%;pzC>$$!Ibb;KhmTgq?% z(@(^&J~BA)DYq32B+}sz($`fP!Q)74U(|?)W${Tm4pl-ox{52X2e@{D?`R<0x~~?2 zNo@aYe-Ni@NR%}d=W$~1IlQIvBOlM9NI^ZA&@+6Ozje$nrr-UtG`dI4`F2F=z1^ZS zXW7A!LChKj>yz$iD%!{!g6&dH=HboSMF6Y~{jL?}ty{xFMS)eoHar#3qJ?pfX0}gZ z&J&RIs-YXGXXAeW>qeeJmYzMe-cqUk%WSPsIqkg_)i0dCtdk!0fblAHYZ#Qab@6~; zZf&2;s4d{GEC#3W>U=v+0G$L3lVow;NYgRFK|WMB)%kJ5A-kIKSniJX%l|sH?S239 zjc*D1B>$%e?xlXD$H|W*WZlEg=U7pv2FbACjI#mxa^pd_Y*kRe63g~H)ooB7FNa&q zvnd#~F;$+h9I$R_ZLO%{xYC&iNhp2moPe?nKgI@49Dh=*vt3gZ{gz`J{yQf z&EE#d;+Y=yXGU;EYP@5Q-?R%<7Dz4)Pe@jQp^&2P!YzisXN_hUYjgUPYulF37?*87Gw(`Ci?kas1~R(Uw1w>fR(-nKUHL(VlP6-jetESs!yc>bLZ zIahM%`Q3F1WZiIwe9D7cG$uC6l@?s$=n-zZSz;?jqFFy^w(rf1s zA)+KoeiKOuq(i#iejz~#Nrz(Y2L+8{7CZhUt=rkAn~o2`-jWq`=p38nO?`yKs;$t| z9B1VCP$GVcCxpZ{W%8VnX$K5(;aU+%i_RPL+kX>F5bBbbcl`|{tGE$Xo@Zy=x?0~Ex?~_ z=r)?_?VR!Q@4Q2tjp2KBES=Bq$M3~&g>L~pn2q6Gw55@iRO6ZR7?)UAJBoU>^cuaS zTlNO49g3yzS!VW4h*b7A%$}3z2bU>>vr+|0k^j7=EB`Yi{vU$of6=Nv|Ctd-{G(Of z|389eE#<|bO&`_+BC;EC2?)yfIJ>Q<%w)64o_NHr;P^i4{U0A4#?cOCyZ6zxIvBm8 z|00AMFAa%FIK6As|L>zarKT?jH~|Eyq6ThYV)LOP0RSMjAYy@VaP3beT{m-bHM_;d zG*S|o;r>{YZuM9-W#V#MT}`e8W|OQEtH@Eel<|zUr2fOiA}R(fM%g9JSfxx;vi_4} zFx`q5pFJi;Ke0wH=o}p5(&uH2j4Z_PqWYCM*I=kBb zE2&*?dMknViPP7&YucmKau**W zW#Km}`8vX8Xx*V|B)tG{Jh7zE8(^a4YQ+_-2R2y?*AXMbx&rKb`o zU%qW?48GLDan?^&SKG6ybD7=cLto2_fNDYxBWLDgS>3r$0w-lwG4#fDKxgHA0Zedo ztp%Op6|)y@>oJzjuUF7GEyi4o_lYU^Iviu{rt0s;97qXF*phOMXVmKuNQTGaHh*=68Iq~OfKR)qmc z80C8QJ^*a!9EY)q%^`nS!O2!$2r+-6>AK`+&yr0%ab!$H9O_1Fu}smu+v^XW<8;(R%V67#hV zu@B?mNRh&;kEu$ta=~Bqlp4CBYvcr_jQ%3=iBjppm;DC9bLvkLgXS$f*TO98`o2tJ z>SzN7CzD!6m&7^{eRRlyPkc{r5>MR2|T6ol`Aq3DjsWtqip_O}oO=Q&8{ z{bKfWBAlKY9gK%EKPo%->RpQ{G`@tLyha4qec-ZG_I*a7b;^TNHT|hay%Y$2Aq}^j zu*sSN3InQz1)0D;`m1nG9wul#`qtcSD%CgFfZbVt%gQY}`Qq5=kdaPChO2v^K`wR# zffT66wVDw+@zvj;sQD3pXfg;#s4>wIHz0e9FeBo&iwAC?_3Fd3Y$l!8T!$Evl#M05 zq^J3pG#V%|aa)T?yBf@?TgpiazwPV{yJQo>2P37l&em=dIUl)KA3=Bt&KkN+2?B9~ zMUAQlb2Gw%nDyv+fa=*_0T*OKO5oO4dQjeq=Ld6`mlv=V_M)89t;98of^p|eJP9f$ zG|!^E{u5+$m-`Ao^v!C@@|6F%+0{H^*KG=qBDdh@jx@XdA`$j*>PDS}GQ%c?@mvXP zgJM**iC_}wi$2(*yx8R{leBc3pFnEYpPW;QKp9nx>-nshVFiHdCJT_;F(rh?)xh_M zi0G**AEA=o-UoR9)`?k4mspW>%h3xzcO$g<*o-sRsI(i>$s|Y}(wJ!Dl3?vT{cPEw zF||QP8G=zuBJN^;6%4mBQ#6vmgYDejB)P>4Z$Ne+nl$V1;V^k3g#t6Y`YavkV_PtB!a>Y$H{nfN%6ze#0WV` zcLUh)wEJ4juy@IP+~C%b3k@0dza`$H&`MF_ri3b*O)Nxkee1*<7Vsi&ExVTi&U&a1 zVd71V@kD(H>qA-ut|+FMbdq;i7EOgO#&|L@!0I{du>g1VRi z?JFFg34RXvf0@t2(7Vgg<^3|BdQ7BZsuZH6;H0^g0ST$J)oEH#Lj{4aQ6A7jJ}iy1 z7L_IU)D<+{sFsBj3tUK18T^IX12<00goB<~$)u*2&OWql-fPmeaZ zCIVZot1`~3TsLttu*#pLP0t6uH>8D6LE#LL&=Cneh~Qr6g`w7dXlq*_VneV}ug)&= zPl3=oTu7W-ANeEBcoV#$1B25R0V4Gl?DYy>@}%bJ9$awJ_cuHK{lTTHO*`4&7uDbo)PvIS6C)sC(&118iCAJhu;C%|2 zBQ?k1XP+ZVUD-JU!2-h1wm(^aM1p2K%DW-p3{b_CGa!@ik0AD;nib0@YtrPZzQSh-WT*%@!A|^0d%pM^@88;_&TFEf zYzDH`*QX3^iATdFaOUwN#)vjFJOK6*zN5o(FJy6w^r84RPp+xerx8`I0n}AtNCXMa zYF1BF*Si9V&Ppol&+8#s4)DyI4Hi+o`yPE?x;Kfsiy z0N0Sp7JrNJhaq!s96Q!u6OU(B8-+)`AV+Z zXeg8(sdORW4+o%>$3}Nc4^}(a_1|I%Jq}122PHB=f*SUo=p?`7t-?!}5tZ4Ssk?!g zdc3mn#89@#9zX2@6wbV;Tn`pRsaP?8v1jJ-h#Rr=?{t8}dzx8huyN}uFd-JXW_pC) zGuRU9@yHW&W)JD0-oTt`f>i2a-t5<-xX9SUG+2gpa*^y{G=hw;yy7d`WXFbK8JyQ* zobFSkhu}j}8Bd4!ile!Xo+G>s{e6A|;t~-%dt8%;`DrQm4>FR7`uZmN=7_5sc7^R8 zJ5iosl;cAtqk_U~=ty^>!2I3T#GAzDA}<5=S1PQD`2f?~#Pzr0(^?#&$;pTUU{Sk= zNYW1KlSD)m+~Tz-k^B+qoU4L$5br$^T9jq4z%ejkoq2}Ku|)L^z~ThoO;_1$+|cYg?#S)olM4pe8JgD*-HA?+gv0S+#wtYxhm0X81DY#@ZNDk zCP8I-ZkcqI-P0N*M-MFApMBVuDIDUof$yq_wTp3N=TFmv9y&afw_c{XUq1{_%d-6L z66sUl?6h6s*7$ohf&=c2&}gqx0_{BRjA0dHDI4>^*SXYYQ0$`=_EF0ATG4`6Fsv!H z;Usn&<-p%r*x(HM9HWV^U)&N$>og+U-cwcbAn>>pCXhgH5T zF!PRATmdP6?~m11hR$a2CctfsnudhvR*%a|PHI$D_GIedG!?3|>w47}%LwOs_y1Wrk(GdP)l9&Lr06@0qmDY^i))?1KtLW zpXwKJm?t1G5E>izYSt(MDHu^XL^M!Cqn%Y;$PMRom7ttQ!YDH6`12dJ1}s4f{$>Ks z$iGNsEaVoPrOR|ZWpJd~t?CI-IuG)b2sYNLGZE;bF|uNI%J=EEX;Sf6B{k&2)Zb$# zH|XcAH9&j%P7J{sofoPK5!He~Q`?^^RKazzVNEvj0s{BjlWmc4SW6%fXml5{v*Z&c z6?iw6FYX*LzrW)I&o;llza77Cro3P`R1!b&x>O8?PrmdI$(q~nw*gUWve|xkW50-O z7PdRH{{AdQo0Xa-YUkNKP2>@KLqZ-{t)N?$BSwE@0`*3pSqPeq-nKn@%-3w#^nZ=#$uZP^Cjn>rTrf^O; zc-ZUfYnJb*+qduXcHt-?W^6=&SsxZOX#YMZya;d)8y(7}+zZmf1tVjgg4Ad#87vI1D#PyqZ~UaG4JWF|!z> zvALkoz`ybem8Nypf8gv&Cw!L{sdzUw!}-u556t4|phX@|;vjl`9bp}nIl3deYH=>o zY*NZ6iC5M^Pu%N;U1_Wti_^oepWHmnw!C*54>BzG_ zI!U*o)&c9~2H*q|F?1mD@;lV8Yk z3Acc?C>FYzU>*nz%&|);ly~ni=kw`czso;_eQ5NGBMzH6A#`R=`Gm{-E9KG#Fw1T* zXRDuv!YM<2>prYE#LN(wcGhf=iGqRcqWoR4NOMN%*Dh#N>@#1t@Pe_2dg8_o(ufvZm*dNydY4`n3KE(QJW-Z2cv zxOF=P)_|RucBT#XitP`NC~5y72`pO%F~;ZtH;CO~P0nR+R`$e!MKwhFDlDA1lezJF z>E9eSxmi}b@G(?lCZ{qG9vjF)!_pP(CZd~L#xq5+yRBh}m_Mg-)v3c+(aLr&eiy@` zxH0snY(OmJko5XUuDKL&%%;{JMy+ z-|VU*xr!6}pK+NAea_d#EJb3Na?w*6BiEbQJtFAb@uZfuj<~3fwN*(PUGDal77Ou2 z_(0FGLVdIOGqPieo9?1UW15NgOSo*FW4;&G1QWmwSfY9E=#~K*n${TEsHk7WK#H-% z>9!2I#NSxhv79a5NtnNp(=VJH^(x?qdgd}K_XZvL>dl+AgV z! zjnlE; zz%}bVQaJdck$6%giKVI|rG@mGx<*saZwz`ni8Lni_~w5}3|I7B|0|AckVeNNqY_CM zJofUQz9z8dBNN(Sp%4o(6f&U2dG@gH<83kLZ*0i)I*e`tHdK;&lyoQrpk_T^)z!#I z8KF{V!AP%R9ih2JJ_+pZ$)yQKWq0tO$5sN@-l=sqXVDOVoKJmpF;Kk$V;m{mR--Yoi_;-WI#TsQ$rH^fOgGIrw&K z7lnFpqjnCUB|%QjLcE_7Rc-q(v(OclYH}7w-$1E!CHw-M7zZcL0juu@w!9O>C@X1V z#haB&YkBB=(n96YG`E|+i_m4_nPr}#q14)Y_uDSSU(6%t6ld>-4=ejbOmux#9e}cJ zJxh1%dGE2_Vcc}drHb6u``aNg32^Z;5tz;#jF8XKH8@l|XxVt!Tv@nYqo|Q2Aj#r+ zp&fl`c@xqMkGZ_0EZzp9hTC!av((C6aC3CNN;d3 zr;vokqF&5Tl;^@g;kE#Lt~D~4A$ieX;!OBTVL27&+PoxQWHB;RO*Em7>?C;yCSyRC zX=YZ23Ot-lDb#MXgeb$qtXg(bRMas=`ogEuwqCWNqzUB@?RW*O92O>KMZ)c8vqoy! zjCp!!Y~+vqOj??`dN&^la{oqN&O)yN_~WY6**q1?eu41C z)8oc@cD#MF`O9ju80ovyayJy~q_o~Rxt2-EYz~K&s6;S4u8MFpeE??Hb9!`yL--%} z2qWx6Oa(E$$9lQRs9+n&3)hIbT%!W9RBQkt^TFD=i*!%H*2asQ`$}r`)3#}$4xZ?u z!juh;*y8m#Yu)llJ|EDF-BzVOj000glTdC#lbzXNC8xsZAeI2gcDc#U7ryrnJanL4 zJm;4>l@j!YWM4kRBlXJ286CD>_NgaV8$EqcHPhtCi(F*%$bEl=D1PL{n9F=_96Z4F zTR18bBR|zxKxeo)(X+;+n03TPX_|-gNg4-kMKy6Paex)V$G(Af_DpRC)HSuVOI4DI zPtv^L6=JcECiH<+b9Xs9*W2b7jwG61%lMC}_3wdnA?c4Jif_$XL^sgLYt<_UMmp4@ z_S%q&PwzI$AG{(1+-jTlX1ClXVe687jb0`Mzc+KgkWkLxH_Acz!=LW#A>iKGN#~gv zEN$!(neBhPX02HR$GKn7qQTSf&7ZP3!*j}8Emvb{&t)7P(*z>6Ps49xh4xx0acUZ@ z!NTx?jiLl6jX;LZR4bxwUB0ExYrV{CZeCmLR3lh?S!!+n%L=&enoekG3&?@37?SDZ$X4)M!hX=qD${GSd)pDQj7$c# z))0lZ>?k4SnC6VlHvJ>9Im?u9!0}AuyLK{?iu;8iLLaGHhTR`I8o=wPlwC6d&_EXg zG0t%pWhZ+|llxSf*1p4N7Y_I92M@h)NTOX(5Kje@Mwr@mF>m5&YV3>8I4&QOY<{gW z3^BaZ{a?*}lB-nLVM9g~e(i%(+2S!+2(%js6_hdw6F!GAaHVZdZ+5Z-L{lpn$kfte zU6*8|ogTnIT6m6n63@eX7Kbx+<4J52Bet?uL%~#Qe?W>tz5ngUXifyC9MBIPM?mN4BE;_016J_W6vl&=YChs_7z4g8fBx zbAs_1x?r#EL3Mq22PE81&~0k{dG20OB7>2dDeP_jkZAFem zK)}l}pNSHgQ0k2d>%WwJSf|nsLvn7z)q$7}6eKCDrHHPrl*00UHIwY*#2bPe%>6&( zs-@%)cH#m9U4F(JN|6jsA0-QE~$jB^8VEQaq$VuEA8 z#!#Fkaef&b0?N`iIUKTlzI318Z%guw`}xHsY4WSlibL{(3Y^y927k#peCZ;C_EbB^ z3zqNS5>*6thMw&*3^i0gcUB7rPm%zT zqz;GI-Q+MeT%EmO^`j#hMi>+iO61=!!~cvc`krTle&EnRbcpQm0c%@7ojn%h=zT

xefwqR&;~$H=kQY8zY(Md&WR9h|F7aqET@0PnZTpBe}SDd zTZzOdk^mraqyiaBp`?FBR~L`V>^BggMT$%g%0xH!-jfeL3Jr-Yi7Xmn2qVQP#3kQ_ zLsh5W2|1*?G_n*7uaa6DQPd!2pFlbdicSGQAOR_%w+|z=d~_2}X}nDB}NkM!&d}xI%eOapQvdOmN@4 z^F{@WyjDYbsznReX>z(2Vne^>5V+AyEBa@i2a?OGv!6@Hi&%>o4G!^fCrrYwu>rTZ zylAfnDHk%kZuXZJ&d9)1VY|2dhYXcCa=Snse@L1U^p!y07LR_Xzg{?alf(p{rU&&m zvfuUSpp2<6Ng|n(Ke&k)xf0^*nBiP&On$Jy`E#!TJj$nn7LgN<{BH$#%r|(%7S5#u z)QX{`$#9a;$mn6>GK1Y`Yo|?ib9i{O0r(xbV%BvIvZv5Xm_{bJU(4f!&0_3{w)<5U z<7+0?bKwBPv0vHW@7cRtjG}PWpB4W+o>ZIabCDg*Zc{Q-{HH+R&LbG{YAaq_0Sm)< z$%Z32LqHgThx|T>5HdcvbRhP;pG3HcnmmWc29$9w`0B6O=lVqfVi^|Zs#%`=(yW(i8H>v6u%nv|1kDT}vA#tJwqu;H7Gf=lI(@uTn2dQ#~vm0e%v zQs)=8W}?*WF%Z+idedOM!m;ao>0x)gZ*ehyTc^CALQ6Oe^$c{GUbW) z;hS$?rW;tpyKQJ^YQuvcc7DF@!cW=OuqVN34q~sSZ9`W$y-l!DRBVe480Axs(MI$} zas_o*r|X*!2!hG4&aITNE8X9(oA>ql+gL)S=v(2S#+Q)e1cHS7<8^P6+dD4Kn!ElW zgLm3DxmW%B^1DSg+>odu{l`Ll~+pm#)%L@@7Mm zF;G)41s^1X(BI_~m&Y;)2enpfaF_E2gsVfcf7o;+AH5m?KXWzL(Y6BJfTw6ht7s@f zBQcXrAYv*=IZh%z-r$80n&sDE6P`nET|11vbPvt5&yIOI!eI2WOWlICMW0B@VekV* zm^Qwr+g`}kJn(acbRQ~_a#B>%RpQQES{`gW;%KC^+N69Y`$OmY*oPo)7*q1sZs4V| z+m?7daf{2fO>D?ip%1$zq@2*1q5j-^E1aBrC;dQE!KKn>&rg>A_Os~u=+w5Cw*H>u zWfxfxVX$!#j`q~t;nOULXGqC2bhPC7hhS6b`P~p}G1vV+^O+eDXN7betE%5fW*NPh z(TKupt?1<)F@cvUDS}=S(JOTz&VoLs{$WK58LRVKiDI`b93q+>J^WXmBMSLrI}_$# zIUqZvu$wRN4hnaU1AOU^zwnKu(8)!lfFYRa`k+LXG6Sfcx`ITo5VqL&ohk}H(H3x3 zk|AU~{24ig3j=w*W5DliF>>VuuQcI3^5h64_e^frsRyG#IV*Xy0SdOi#jIHv+8v!onS&NVE*oE%@O&C7DwERiYP)FuLAx-KRRZ5twF-tjPC1It ze*5)iAW-KUjN-t>dXPWLJPQ7dcN@N{UV{p7?lbg9VtR&fX7YdJ>O&}{ zJ0HN;|3ZVMoeN3&dZ;5Yc_5frYJdIfx6dL(hm|D~*Gu;86HtzsGuzvR^$<9&Eun(S z4}}WLC6Wtw7#S`wYy~>mJE33yXDJH@Ek%^YFa4>o4RN7mybl-_-$JLuWFojXjyH({ z&9wKiP2iF=K6{t5aA;w~Jr2vBqmN;q4=2558P+l(v9i4pUY;^kb02GN%!p2YDReW- zwuXZ0bo!-&Y*+CNCy8=%%3AQVPCEFjySREQG8zt8CyI0w4Nb5fXhP}_TF)X7whLL6 z)#C7Xj=YY^y>t54x|m2$rlZusLYuo_LnnBf&ezyaspMFbSf^RkqszIPA4_B(cj*p=ZbheTR8YXCD7hMMr=buMN^r) zV0J+7Pa~_{Hu{mDDIPuzU3W>^q0M{3rVTw+;OA{6WBpVf30uRKgH1L}^5mokRizwQ z4(TIUD8ZCKXi1(1jJ&DZW+ebQizW@U?ol90@8Oi(pj^AD$8G`f8RdFA;3BjPJRAO) z9-hl@4mva<+1B+4Jjdl@`LAXwcIH^gE1}NEgE9_ynHkaH(YfiBo@)MJ?r78(w;lNT zmq*1bqVU|xpx_e;sJaML+15i?0O{hnTSPJmpk%T}AylJdFe&|bmnmSFoVuCR=5|8a zDytQa$n!Tm|Ii#*i`TW0;Ey7zncId?;3Mf6LlkiK5K%kTSQz3H_umvqaIuX}A;Kme%r)1SR=fo%!MAt!cBjJ#3g9e(m z)BdqWq@f@U_)hI^uApEdjE#G89EPV%{0r-TV7u>`xlt-)*;1){t;Ds6WhgBcbYK-S zO3#Qa3V{6KI5tFMs1%;BbmrWTK``x= z?LTFjVLR z^jG}QH;Kg^#}7faa+`}DT9d9=+B`+xn2*nsyP^&_stQIlgdY!hpo=!VCm!JOM5RWI z;DP{2Fi5o`-!WG7=oT`v`|SpV!#ilam!byy$IBXS_im76HxC^Ke3s-+n(=3D>HXBAohlIGf1%FHx<>ImAAvUL}}>M{Uu`p6)g zs$IWI&V9xpytHUDw_EQnl6P^+Ey3RBlE9XQ--1~Z7J*hAiH8k z5!_RXcHcJ%<(hLyn9oN}$s8GpZ!qu^w>MVsqO^+RzIE zr>;!IL63E;KbwvCfOBZ@l`U}4L(yTxrTIw|R_rIR7;Q^^>*X6>ZyLlE+2VqP3L((~ ze8G7(08x)Gh7IcRVuz_55;CR-vV_Ipg<9Hz6cF%S5g^@A%^%q56AOpwpe-;iJE&34 z>Sa$qRwQaPd7;Ci?eZtJC!W;!;z_x(JMj74bnjQ7q2sxvr=<9+h@3TS=|RGRgCwIt+=|pT|+L7bs6ch-I{Ihg^EkdUd4O^%!$4a z^XF%D}pVIA_ciX8DXSFUzum5y3-!Edfeh3I+QyzU7EAAiKl*4VsY8+-T3A zGo0v?*Qcns*(!*8b}`;F_$ft(Qv$j2s+VC{YKcWXjERa@oEvz;%dB_KeTDHbD#=-} zVlHzNtKa1nfy*cS1=uCrdF7#okr_5nW}RZl!g8G1**U7ijx2-btjjRyY%NYCh7(?& z+^b|2`A6>6jhx^o)S`pfTThxhBVaRO0ME`5_D%?yYl<0mo^ga*$u6hr&v&C<`wVV( z+RlBc^hI_rPQ%#fF7Q0)kh7@&#AWsE1ZIVDEBQw`PvGSv7w2q)j_9yr(84lTW;R2^ ziNL4yE2Ep)utuuLzvh}0ymC^vp>6hJM_Km1_-#dg;|aC#?u3f@4w)k;O#dY%P#E7$ zzj$)hdsV!tT$a_XN=+9G=O=b znPa>F_u2*A#%?OeTwH_WvB!88Sdza0n6QYS0NaBMr!5~fhw(e<8P(N&=n>%=(2sZ- z%-tIX)!?qEL?`;>JW9ivKFqhGzb4u$1Ss&*+hi9TU@@;Cz4?j5lGnnVV+*F0> z!I@nc@3Icq4$Co~O#~NrSZT@OM)w+^&R(;r0T%Dzmj&f&bHsK1D1+>mFD!$~PLvg> zY%{?~Y^6Ebb^H10g=_cbyK?i;>4*)1y*YYkWQ04nnaR;D7N)x>m@Kwf7@s*8)6M#@ znRYwgXg-M7cxT@g-@6Fqp_Wb2Rdw=-dz6i5KvxF&%yn^bw<_271s@2`;)rf6r71y? zKh*7~t|d{NROo8*27FGJygT@Ux>FqRxd3PYOXEcd62j;5CLz1y)Dwb3!cv3)fo8N2 z2he~#fO)e?ojYd|!{o3I1V_Y?1_hQup>5E&`d>qgTgh?VtJGyRMG-W00!}ONfBMsc z%7)k|M@Sk_KA<=fd>rGNs;WWZC}x)fv(SdonfhIXl&%}YSsFKzmXy&)b_UNhu0wL` zYMn9lS?-)tn&(MFJrx1PM=UEMPeU1$DcsC9=nQ-SrDHzKx`@*6!%wY4!>2gcnMmSL zyB4E@kGHKSS24A&d_}4I_}{{DrQ4jyeFA7L>OE|BTFe!9LHqRK1kE&jQ9sW~Q0|!A9lJBj4Rh@cNJx^H zRmsr?y9QFPi&ITwP`LpSDqk4QBrq?*TGDU4F}XYTX0{T7YdtEVl#GcduC`Q{&<0C_ zP)Y``l^&9YMhIer!;9nej33t>WEv{_u$+k4K88IpA98aA<{ z6~B-Bg2~;n3$uK+5#ptccqK^1Qk(M1XV6o28&C^8oPgXiQ@6HmcbmBGpw_{*PVN?# zF{c1RZQ`do|1imuqy~mA)25r z+2t1k-dhjMC^QkTKEx1|;NA8hhlIhP_!B{U^g#o`3nz!f3m1PT>lOU3JffqVY8F&-Rhj~y|>*xbpKZqfj_`uSv^(ii2lohB)M*z-GnaF zqBM5^0T4hQ->xgTW_BIU$3L|E-~96cssAaJdYN<_g9c2u$sz;ZBE2viiM9G`O~Q2}Fe zV{6Aef&xc?;O&THprRQ20h5q1D{_}3m{E^zld>|5GPEUvZ8iF)6u=aovDfKf=my46 zgeX9M`Vg_7ICJq;47eGk_F?ln)tlcpBOf7R)zCkVdG%q}qfjMYYP*9=<~AVE4tGv@ zb?yeWtm6#8u13byL!L70kzvgW&9_GqM!=m`VX)IWGOOgh2pJ9rH^mT@ed(4mfSDJ0 zrRE@_M*=6!iGv>sX2y8s5#cGy1Z8UIp|6Fak53JZiBOSO^*|>mZ@}CQ{P`g@HRl>&z-l&vBUd9wH(k1T$@~rPK0*LM#@gUc3#kgJhw&iCc`Th1N-0+be zK|V2x+FOR8M+mE?Ed0uZ+))t@k$aJO{94!VDN9d{xmwrtBeUt; zhvXq31a=bsI-}qV@D@e$ER;hGucplW3?X>+#1ef%FsjGwp>wwa!3b74kVUJ59NN`8 z&u?EG3K1xL5uvBDL18twOb&+^A>W)C5d5l2=9K6$5q-UALh?9vPG6}fJCNv%FvOR= zyE2&|NX6I;Az6XrlCiqlo!f*<0YecG@L3{dv|s8YzZJlQ5R5^OM7&Cewh$N9Att@W zg^XfnvWC^X1Wh|Yf0jWM$@DsNMdPLj;apR=!o}gwJVJ=6Czw&^`&k*5Yn(W+!YO~f z`t)V?WDu2Ke>!DizauL>Ocpkh1AM%oUJq0c}GOiZ|scd1qvWpuE=w#3@satknV) z{LnRgH!5Q{(Y=_69YqQ3I^U&kpUxWPAK&>37gO2^IU~H zI&U?Y*4j-X3j94D6=T*$RtD01A!3D9^A*7V5YalAU1dL0M1|=6AvsKtz-cE4rLd!k zlgJ9n&6kdHcrl1;def9wJ`jDlX#)AZ8mTBtbeb&@6|Sk*Y&B;TLM_L{lQBz-65J?gL&^BhBTrq+IYIUMgO4*EmMk0C9FB zP!F9G!c*N^cnafbFe%qTmT$Eh6{qJe>&7fd)CgDc2LkuBET%a?-0Yn;iDiOAb=#i2gjXRZ_ z9+Us^guCoCWnr%|5VaDQc}+QnyDwo>nxJl)ay$*#1ExDn!xveF_)wSVg(lJtD6xeu z2#Hlgg{mNCAs_0lIk>~Q8ALsng0gnBP82DMM?_PIA>Kii5NQHS8~2c!%A&n3<$_w- z6fk7QCQGQebW+#eo6qlFq(q(Z&^e)(YmytQCS|aLNq0KH;tmNf|AS5C7;=wYS0RvC zNxI1foCl1$zGxy%l>HNmwa$XCh-NiAop#tMS32>uYTgH=`w4IM6cy@>$RT7gPTwkQ zk-~-h+WUauo7{^O{;?D>K>?Y_z*Z=yGXbY{!z-@_1SH}!f)YUGn``?(1W7Z=(>#iL zQrIdg`T^zQM<&X+^Cpp}fGtj|gg0(^K1DSn8@mm3LSkCvKGq?Y^0(0O3c<+4i~7qi+PkcebMy} zT~7RKC)3-weod`r{6U!p<_&_fvoXfB#GCa=^g5iYrF5McB^T!tZnAj8HK1|^_fw<&oqhyLA=a5r@_VQUU>Oxo3i-07q^ z;4Dx(8Y{cc`40Uyg)ufQX7>@LKttW7z|;+-8ainIIF# zt?|~Y{1nBwu#nqT^KN07)b7{L>mT`DB$`+Mub?^IYuc8I{g@52Xy(9B)M8FEO%YfD z7j6^T|5Fshu2@kXMutifjOM8tGSLFFk?o>c0lcX1l0Ty2X$^wPK*J`2MIiQ3nhbNC zPUQZdkdFcXXOfryd-=crPVMfu6}tbYW4|Va-5h$~wYl3t?e6}cjsd&-tsC_Jv^>T8 dZu!5L%ewpRmOjp*8ojpeW|#K=#C%NXxe+(9v(Nwl literal 0 HcmV?d00001 diff --git a/test/unit/image-optimizer/images/test.jpg b/test/unit/image-optimizer/images/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d536c882412ed3df0dc162823ca5146bcc033499 GIT binary patch literal 6765 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 literal 0 HcmV?d00001 diff --git a/test/unit/image-optimizer/images/test.svg b/test/unit/image-optimizer/images/test.svg new file mode 100644 index 0000000000..a9b392f1aa --- /dev/null +++ b/test/unit/image-optimizer/images/test.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/test/unit/image-rendering.unit.test.js b/test/unit/image-rendering.test.ts similarity index 100% rename from test/unit/image-rendering.unit.test.js rename to test/unit/image-rendering.test.ts diff --git a/test/unit/is-serializable-props.unit.test.js b/test/unit/is-serializable-props.test.ts similarity index 97% rename from test/unit/is-serializable-props.unit.test.js rename to test/unit/is-serializable-props.test.ts index 5cc96e66e3..4ff2b8e640 100644 --- a/test/unit/is-serializable-props.unit.test.js +++ b/test/unit/is-serializable-props.test.ts @@ -175,7 +175,7 @@ describe('isSerializableProps', () => { }) it('can handle obj circular refs', () => { - const obj = { foo: 'bar', test: true } + const obj: any = { foo: 'bar', test: true } obj.child = obj expect(() => isSerializableProps('/', 'test', obj)) @@ -192,7 +192,7 @@ describe('isSerializableProps', () => { }) it('can handle arr circular refs', () => { - const arr = [{ foo: 'bar' }, true] + const arr: any = [{ foo: 'bar' }, true] arr.push(arr) expect(() => isSerializableProps('/', 'test', { arr })) @@ -209,7 +209,7 @@ describe('isSerializableProps', () => { }) it('can handle deep obj circular refs', () => { - const obj = { foo: 'bar', test: true, leve1: { level2: {} } } + const obj: any = { foo: 'bar', test: true, leve1: { level2: {} } } obj.leve1.level2.child = obj expect(() => isSerializableProps('/', 'test', obj)) @@ -220,7 +220,7 @@ describe('isSerializableProps', () => { }) it('can handle deep obj circular refs (with arrays)', () => { - const obj = { foo: 'bar', test: true, leve1: { level2: {} } } + const obj: any = { foo: 'bar', test: true, leve1: { level2: {} } } obj.leve1.level2.child = [{ another: [obj] }] expect(() => isSerializableProps('/', 'test', obj)) diff --git a/test/isolated/.gitignore b/test/unit/isolated/.gitignore similarity index 100% rename from test/isolated/.gitignore rename to test/unit/isolated/.gitignore diff --git a/test/isolated/_resolvedata/.gitignore b/test/unit/isolated/_resolvedata/.gitignore similarity index 100% rename from test/isolated/_resolvedata/.gitignore rename to test/unit/isolated/_resolvedata/.gitignore diff --git a/test/isolated/_resolvedata/aa/cache.js b/test/unit/isolated/_resolvedata/aa/cache.js similarity index 100% rename from test/isolated/_resolvedata/aa/cache.js rename to test/unit/isolated/_resolvedata/aa/cache.js diff --git a/test/isolated/_resolvedata/aa/index.js b/test/unit/isolated/_resolvedata/aa/index.js similarity index 100% rename from test/isolated/_resolvedata/aa/index.js rename to test/unit/isolated/_resolvedata/aa/index.js diff --git a/test/isolated/_resolvedata/bb/index.json b/test/unit/isolated/_resolvedata/bb/index.json similarity index 100% rename from test/isolated/_resolvedata/bb/index.json rename to test/unit/isolated/_resolvedata/bb/index.json diff --git a/test/isolated/_resolvedata/cache/test.txt b/test/unit/isolated/_resolvedata/cache/test.txt similarity index 100% rename from test/isolated/_resolvedata/cache/test.txt rename to test/unit/isolated/_resolvedata/cache/test.txt diff --git a/test/isolated/_resolvedata/cc/index.js b/test/unit/isolated/_resolvedata/cc/index.js similarity index 100% rename from test/isolated/_resolvedata/cc/index.js rename to test/unit/isolated/_resolvedata/cc/index.js diff --git a/test/isolated/_resolvedata/cc/index.json b/test/unit/isolated/_resolvedata/cc/index.json similarity index 100% rename from test/isolated/_resolvedata/cc/index.json rename to test/unit/isolated/_resolvedata/cc/index.json diff --git a/test/isolated/_resolvedata/invalid-target/next.config.js b/test/unit/isolated/_resolvedata/invalid-target/next.config.js similarity index 100% rename from test/isolated/_resolvedata/invalid-target/next.config.js rename to test/unit/isolated/_resolvedata/invalid-target/next.config.js diff --git a/test/isolated/_resolvedata/js-ts-config/next.config.js b/test/unit/isolated/_resolvedata/js-ts-config/next.config.js similarity index 100% rename from test/isolated/_resolvedata/js-ts-config/next.config.js rename to test/unit/isolated/_resolvedata/js-ts-config/next.config.js diff --git a/test/isolated/_resolvedata/js-ts-config/next.config.json b/test/unit/isolated/_resolvedata/js-ts-config/next.config.json similarity index 100% rename from test/isolated/_resolvedata/js-ts-config/next.config.json rename to test/unit/isolated/_resolvedata/js-ts-config/next.config.json diff --git a/test/isolated/_resolvedata/js-ts-config/next.config.jsx b/test/unit/isolated/_resolvedata/js-ts-config/next.config.jsx similarity index 100% rename from test/isolated/_resolvedata/js-ts-config/next.config.jsx rename to test/unit/isolated/_resolvedata/js-ts-config/next.config.jsx diff --git a/test/isolated/_resolvedata/js-ts-config/next.config.ts b/test/unit/isolated/_resolvedata/js-ts-config/next.config.ts similarity index 100% rename from test/isolated/_resolvedata/js-ts-config/next.config.ts rename to test/unit/isolated/_resolvedata/js-ts-config/next.config.ts diff --git a/test/isolated/_resolvedata/js-ts-config/next.config.tsx b/test/unit/isolated/_resolvedata/js-ts-config/next.config.tsx similarity index 100% rename from test/isolated/_resolvedata/js-ts-config/next.config.tsx rename to test/unit/isolated/_resolvedata/js-ts-config/next.config.tsx diff --git a/test/isolated/_resolvedata/one.js b/test/unit/isolated/_resolvedata/one.js similarity index 100% rename from test/isolated/_resolvedata/one.js rename to test/unit/isolated/_resolvedata/one.js diff --git a/test/isolated/_resolvedata/one.json b/test/unit/isolated/_resolvedata/one.json similarity index 100% rename from test/isolated/_resolvedata/one.json rename to test/unit/isolated/_resolvedata/one.json diff --git a/test/isolated/_resolvedata/readdir/pages/index.js b/test/unit/isolated/_resolvedata/readdir/pages/index.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/index.js rename to test/unit/isolated/_resolvedata/readdir/pages/index.js diff --git a/test/isolated/_resolvedata/readdir/pages/nav/about.js b/test/unit/isolated/_resolvedata/readdir/pages/nav/about.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/nav/about.js rename to test/unit/isolated/_resolvedata/readdir/pages/nav/about.js diff --git a/test/isolated/_resolvedata/readdir/pages/nav/index.js b/test/unit/isolated/_resolvedata/readdir/pages/nav/index.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/nav/index.js rename to test/unit/isolated/_resolvedata/readdir/pages/nav/index.js diff --git a/test/isolated/_resolvedata/readdir/pages/nav/products/product.js b/test/unit/isolated/_resolvedata/readdir/pages/nav/products/product.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/nav/products/product.js rename to test/unit/isolated/_resolvedata/readdir/pages/nav/products/product.js diff --git a/test/isolated/_resolvedata/readdir/pages/nested/index.js b/test/unit/isolated/_resolvedata/readdir/pages/nested/index.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/nested/index.js rename to test/unit/isolated/_resolvedata/readdir/pages/nested/index.js diff --git a/test/isolated/_resolvedata/readdir/pages/prefered.js b/test/unit/isolated/_resolvedata/readdir/pages/prefered.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/prefered.js rename to test/unit/isolated/_resolvedata/readdir/pages/prefered.js diff --git a/test/isolated/_resolvedata/readdir/pages/prefered/index.js b/test/unit/isolated/_resolvedata/readdir/pages/prefered/index.js similarity index 100% rename from test/isolated/_resolvedata/readdir/pages/prefered/index.js rename to test/unit/isolated/_resolvedata/readdir/pages/prefered/index.js diff --git a/test/isolated/_resolvedata/server/pages-manifest.json b/test/unit/isolated/_resolvedata/server/pages-manifest.json similarity index 100% rename from test/isolated/_resolvedata/server/pages-manifest.json rename to test/unit/isolated/_resolvedata/server/pages-manifest.json diff --git a/test/isolated/_resolvedata/server/static/development/pages/_error.js b/test/unit/isolated/_resolvedata/server/static/development/pages/_error.js similarity index 100% rename from test/isolated/_resolvedata/server/static/development/pages/_error.js rename to test/unit/isolated/_resolvedata/server/static/development/pages/_error.js diff --git a/test/isolated/_resolvedata/server/static/development/pages/index.js b/test/unit/isolated/_resolvedata/server/static/development/pages/index.js similarity index 100% rename from test/isolated/_resolvedata/server/static/development/pages/index.js rename to test/unit/isolated/_resolvedata/server/static/development/pages/index.js diff --git a/test/isolated/_resolvedata/server/static/development/pages/non-existent-child.js b/test/unit/isolated/_resolvedata/server/static/development/pages/non-existent-child.js similarity index 100% rename from test/isolated/_resolvedata/server/static/development/pages/non-existent-child.js rename to test/unit/isolated/_resolvedata/server/static/development/pages/non-existent-child.js diff --git a/test/isolated/_resolvedata/server/static/development/pages/world.js b/test/unit/isolated/_resolvedata/server/static/development/pages/world.js similarity index 100% rename from test/isolated/_resolvedata/server/static/development/pages/world.js rename to test/unit/isolated/_resolvedata/server/static/development/pages/world.js diff --git a/test/isolated/_resolvedata/two.json b/test/unit/isolated/_resolvedata/two.json similarity index 100% rename from test/isolated/_resolvedata/two.json rename to test/unit/isolated/_resolvedata/two.json diff --git a/test/isolated/_resolvedata/typescript-config/next.config.ts b/test/unit/isolated/_resolvedata/typescript-config/next.config.ts similarity index 100% rename from test/isolated/_resolvedata/typescript-config/next.config.ts rename to test/unit/isolated/_resolvedata/typescript-config/next.config.ts diff --git a/test/isolated/_resolvedata/valid-target/next.config.js b/test/unit/isolated/_resolvedata/valid-target/next.config.js similarity index 100% rename from test/isolated/_resolvedata/valid-target/next.config.js rename to test/unit/isolated/_resolvedata/valid-target/next.config.js diff --git a/test/isolated/_resolvedata/with-function/next.config.js b/test/unit/isolated/_resolvedata/with-function/next.config.js similarity index 100% rename from test/isolated/_resolvedata/with-function/next.config.js rename to test/unit/isolated/_resolvedata/with-function/next.config.js diff --git a/test/isolated/_resolvedata/without-function/next.config.js b/test/unit/isolated/_resolvedata/without-function/next.config.js similarity index 100% rename from test/isolated/_resolvedata/without-function/next.config.js rename to test/unit/isolated/_resolvedata/without-function/next.config.js diff --git a/test/isolated/config.unit.test.js b/test/unit/isolated/config.test.ts similarity index 100% rename from test/isolated/config.unit.test.js rename to test/unit/isolated/config.test.ts diff --git a/test/isolated/require-page.unit.test.js b/test/unit/isolated/require-page.test.ts similarity index 83% rename from test/isolated/require-page.unit.test.js rename to test/unit/isolated/require-page.test.ts index f396a7faa6..33c8ba1fb1 100644 --- a/test/isolated/require-page.unit.test.js +++ b/test/unit/isolated/require-page.test.ts @@ -1,13 +1,13 @@ /* eslint-env jest */ import { join } from 'path' +import { normalizePagePath } from 'next/dist/server/normalize-page-path' import { SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH } from 'next/constants' import { requirePage, getPagePath, pageNotFoundError, } from 'next/dist/server/require' -import { normalizePagePath } from 'next/dist/server/normalize-page-path' const sep = '/' const distDir = join(__dirname, '_resolvedata') @@ -55,42 +55,42 @@ describe('normalizePagePath', () => { describe('getPagePath', () => { it('Should not append /index to the / page', () => { - expect(() => getPagePath('/', distDir)).toThrow( + expect(() => getPagePath('/', distDir, false)).toThrow( 'Cannot find module for page: /' ) }) it('Should prepend / when a page does not have it', () => { - const pagePath = getPagePath('_error', distDir) + const pagePath = getPagePath('_error', distDir, false) expect(pagePath).toBe(join(pathToBundles, `${sep}_error.js`)) }) it('Should throw with paths containing ../', () => { - expect(() => getPagePath('/../../package.json', distDir)).toThrow() + expect(() => getPagePath('/../../package.json', distDir, false)).toThrow() }) }) describe('requirePage', () => { it('Should not find page /index when using /', async () => { - await expect(() => requirePage('/', distDir)).toThrow( + await expect(() => requirePage('/', distDir, false)).toThrow( 'Cannot find module for page: /' ) }) it('Should require /index.js when using /index', async () => { - const page = await requirePage('/index', distDir) + const page = await requirePage('/index', distDir, false) expect(page.test).toBe('hello') }) it('Should require /world.js when using /world', async () => { - const page = await requirePage('/world', distDir) + const page = await requirePage('/world', distDir, false) expect(page.test).toBe('world') }) it('Should throw when using /../../test.js', async () => { expect.assertions(1) try { - await requirePage('/../../test', distDir) + await requirePage('/../../test', distDir, false) } catch (err) { // eslint-disable-next-line jest/no-try-expect expect(err.code).toBe('ENOENT') @@ -100,7 +100,7 @@ describe('requirePage', () => { it('Should throw when using non existent pages like /non-existent.js', async () => { expect.assertions(1) try { - await requirePage('/non-existent', distDir) + await requirePage('/non-existent', distDir, false) } catch (err) { // eslint-disable-next-line jest/no-try-expect expect(err.code).toBe('ENOENT') @@ -110,7 +110,7 @@ describe('requirePage', () => { it('Should bubble up errors in the child component', async () => { expect.assertions(1) try { - await requirePage('/non-existent-child', distDir) + await requirePage('/non-existent-child', distDir, false) } catch (err) { // eslint-disable-next-line jest/no-try-expect expect(err.code).toBe('MODULE_NOT_FOUND') diff --git a/test/unit/link-rendering.unit.test.js b/test/unit/link-rendering.test.ts similarity index 100% rename from test/unit/link-rendering.unit.test.js rename to test/unit/link-rendering.test.ts diff --git a/test/unit/link-warnings.test.js b/test/unit/link-warnings.test.tsx similarity index 100% rename from test/unit/link-warnings.test.js rename to test/unit/link-warnings.test.tsx diff --git a/test/unit/loadGetInitialProps.unit.test.js b/test/unit/loadGetInitialProps.test.ts similarity index 80% rename from test/unit/loadGetInitialProps.unit.test.js rename to test/unit/loadGetInitialProps.test.ts index 8f7a42690b..d9cbc62294 100644 --- a/test/unit/loadGetInitialProps.unit.test.js +++ b/test/unit/loadGetInitialProps.test.ts @@ -6,7 +6,7 @@ describe('loadGetInitialProps', () => { class TestComponent { getInitialProps() {} } - const rejectPromise = loadGetInitialProps(TestComponent, {}) + const rejectPromise = loadGetInitialProps(TestComponent as any, {}) const error = new Error( '"TestComponent.getInitialProps()" is defined as an instance method - visit https://nextjs.org/docs/messages/get-initial-props-as-an-instance-method for more information.' ) @@ -14,7 +14,7 @@ describe('loadGetInitialProps', () => { }) it('should resolve to an empty object if getInitialProps is missing', async () => { - const result = await loadGetInitialProps(() => {}, {}) + const result = await loadGetInitialProps((() => {}) as any, {}) expect(result).toEqual({}) }) @@ -24,7 +24,7 @@ describe('loadGetInitialProps', () => { return { foo: 1 } } } - const result = await loadGetInitialProps(TestComponent, {}) + const result = await loadGetInitialProps(TestComponent as any, {}) expect(result).toEqual({ foo: 1 }) }) @@ -34,12 +34,12 @@ describe('loadGetInitialProps', () => { return 'invalidValue' } } - const ctx = { + const ctx: any = { res: { finished: true, }, } - const result = await loadGetInitialProps(TestComponent, ctx) + const result = await loadGetInitialProps(TestComponent as any, ctx) expect(result).toBe('invalidValue') }) @@ -47,7 +47,7 @@ describe('loadGetInitialProps', () => { class TestComponent { static async getInitialProps() {} } - const rejectPromise = loadGetInitialProps(TestComponent, {}) + const rejectPromise = loadGetInitialProps(TestComponent as any, {}) const error = new Error( '"TestComponent.getInitialProps()" should resolve to an object. But found "undefined" instead.' ) diff --git a/test/unit/mitt.unit.test.js b/test/unit/mitt.test.ts similarity index 100% rename from test/unit/mitt.unit.test.js rename to test/unit/mitt.test.ts diff --git a/test/unit/next-babel-loader.unit.test.js b/test/unit/next-babel-loader.test.ts similarity index 98% rename from test/unit/next-babel-loader.unit.test.js rename to test/unit/next-babel-loader.test.ts index 873850fa09..6c17e80955 100644 --- a/test/unit/next-babel-loader.unit.test.js +++ b/test/unit/next-babel-loader.test.ts @@ -1,17 +1,11 @@ /* eslint-env jest */ -function interopRequireDefault(mod) { - return mod.default || mod -} - -const loader = interopRequireDefault( - require('next/dist/build/webpack/loaders/next-babel-loader') -) -const os = require('os') -const path = require('path') +import os from 'os' +import path from 'path' +import loader from 'next/dist/build/webpack/loaders/next-babel-loader' const dir = path.resolve(os.tmpdir()) -const babel = async (code, queryOpts = {}) => { +const babel = async (code: string, queryOpts = {} as any) => { const { isServer = false, resourcePath = 'index.js', @@ -19,7 +13,7 @@ const babel = async (code, queryOpts = {}) => { } = queryOpts let isAsync = false - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { function callback(err, content) { if (err) { reject(err) diff --git a/test/unit/next-babel.unit.test.js b/test/unit/next-babel.test.ts similarity index 98% rename from test/unit/next-babel.unit.test.js rename to test/unit/next-babel.test.ts index 6720603350..3bc39d33a4 100644 --- a/test/unit/next-babel.unit.test.js +++ b/test/unit/next-babel.test.ts @@ -1,10 +1,10 @@ /* eslint-env jest */ -import { transform } from '@babel/core' +import { transformSync } from '@babel/core' const trim = (s) => s.join('\n').trim().replace(/^\s+/gm, '') const babel = (code, esm = false, presetOptions = {}, filename = 'noop.js') => - transform(code, { + transformSync(code, { filename, presets: [[require('next/dist/build/babel/preset'), presetOptions]], babelrc: false, @@ -16,7 +16,7 @@ const babel = (code, esm = false, presetOptions = {}, filename = 'noop.js') => supportsStaticESM: esm, isDev: false, }, - }).code + } as any).code describe('next/babel', () => { describe('jsx-pragma', () => { diff --git a/test/unit/next-dynamic.test.js b/test/unit/next-dynamic.test.tsx similarity index 100% rename from test/unit/next-dynamic.test.js rename to test/unit/next-dynamic.test.tsx diff --git a/test/unit/next-head-rendering.unit.test.js b/test/unit/next-head-rendering.test.ts similarity index 91% rename from test/unit/next-head-rendering.unit.test.js rename to test/unit/next-head-rendering.test.ts index 128dc01ec3..3ab3ebb54b 100644 --- a/test/unit/next-head-rendering.unit.test.js +++ b/test/unit/next-head-rendering.test.ts @@ -9,7 +9,7 @@ describe('Rendering next/head', () => { React.createElement( React.Fragment, {}, - React.createElement(Head, {}), + React.createElement(Head), React.createElement('p', {}, 'hello world') ) ) diff --git a/test/unit/next-server-utils.unit.test.js b/test/unit/next-server-utils.test.ts similarity index 100% rename from test/unit/next-server-utils.unit.test.js rename to test/unit/next-server-utils.test.ts diff --git a/test/unit/next-swc.unit.test.js b/test/unit/next-swc.test.ts similarity index 100% rename from test/unit/next-swc.unit.test.js rename to test/unit/next-swc.test.ts diff --git a/test/unit/oxford-comma.unit.test.js b/test/unit/oxford-comma.test.ts similarity index 100% rename from test/unit/oxford-comma.unit.test.js rename to test/unit/oxford-comma.test.ts diff --git a/test/unit/page-route-sorter.unit.test.js b/test/unit/page-route-sorter.test.ts similarity index 100% rename from test/unit/page-route-sorter.unit.test.js rename to test/unit/page-route-sorter.test.ts diff --git a/test/unit/parse-relative-url.unit.test.js b/test/unit/parse-relative-url.test.ts similarity index 96% rename from test/unit/parse-relative-url.unit.test.js rename to test/unit/parse-relative-url.test.ts index 3d1097ecb2..5343ec49ce 100644 --- a/test/unit/parse-relative-url.unit.test.js +++ b/test/unit/parse-relative-url.test.ts @@ -4,7 +4,7 @@ import { parseRelativeUrl } from 'next/dist/shared/lib/router/utils/parse-relati // convenience function so tests can be aligned neatly // and easy to eyeball const check = (windowUrl, targetUrl, expected) => { - window.location = new URL(windowUrl) + window.location = new URL(windowUrl) as any if (typeof expected === 'string') { expect(() => parseRelativeUrl(targetUrl)).toThrow(expected) } else { @@ -17,13 +17,13 @@ const check = (windowUrl, targetUrl, expected) => { describe('parseRelativeUrl', () => { beforeAll(() => { - global.window = { + ;(global as any).window = { location: {}, } }) afterAll(() => { - delete global.window + delete (global as any).window }) it('should parse relative url', () => { diff --git a/test/unit/phaseConstants.unit.test.js b/test/unit/phaseConstants.test.ts similarity index 100% rename from test/unit/phaseConstants.unit.test.js rename to test/unit/phaseConstants.test.ts diff --git a/test/unit/recursive-copy.unit.test.js b/test/unit/recursive-copy.test.ts similarity index 100% rename from test/unit/recursive-copy.unit.test.js rename to test/unit/recursive-copy.test.ts diff --git a/test/unit/recursive-delete.unit.test.js b/test/unit/recursive-delete.test.ts similarity index 84% rename from test/unit/recursive-delete.unit.test.js rename to test/unit/recursive-delete.test.ts index 3369f0864c..a2c4f7f43d 100644 --- a/test/unit/recursive-delete.unit.test.js +++ b/test/unit/recursive-delete.test.ts @@ -4,9 +4,9 @@ import { recursiveReadDir } from 'next/dist/lib/recursive-readdir' import { recursiveCopy } from 'next/dist/lib/recursive-copy' import { join } from 'path' -const resolveDataDir = join(__dirname, '..', 'isolated', '_resolvedata') -const testResolveDataDir = join(__dirname, '..', 'isolated', 'test_resolvedata') -const testpreservefileDir = join(__dirname, '..', 'isolated', 'preservefiles') +const resolveDataDir = join(__dirname, 'isolated', '_resolvedata') +const testResolveDataDir = join(__dirname, 'isolated', 'test_resolvedata') +const testpreservefileDir = join(__dirname, 'isolated', 'preservefiles') describe('recursiveDelete', () => { it('should work', async () => { diff --git a/test/unit/recursive-readdir.unit.test.js b/test/unit/recursive-readdir.test.ts similarity index 91% rename from test/unit/recursive-readdir.unit.test.js rename to test/unit/recursive-readdir.test.ts index ce0c15b54f..dae120bb2b 100644 --- a/test/unit/recursive-readdir.unit.test.js +++ b/test/unit/recursive-readdir.test.ts @@ -3,7 +3,7 @@ import { recursiveReadDir } from 'next/dist/lib/recursive-readdir' import { join } from 'path' -const resolveDataDir = join(__dirname, '..', 'isolated', '_resolvedata') +const resolveDataDir = join(__dirname, 'isolated', '_resolvedata') const dirWithPages = join(resolveDataDir, 'readdir', 'pages') jest.setTimeout(1000 * 60 * 5) diff --git a/test/unit/router-add-base-path.unit.test.js b/test/unit/router-add-base-path.test.ts similarity index 100% rename from test/unit/router-add-base-path.unit.test.js rename to test/unit/router-add-base-path.test.ts diff --git a/test/unit/webpack-config-overrides.unit.test.js b/test/unit/webpack-config-overrides.test.ts similarity index 100% rename from test/unit/webpack-config-overrides.unit.test.js rename to test/unit/webpack-config-overrides.test.ts diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..c78ab1f7d3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "strict": false, + "noEmit": true, + "allowJs": true, + "jsx": "react", + "module": "esnext", + "skipLibCheck": true, + "esModuleInterop": true, + "moduleResolution": "node", + "baseUrl": ".", + "paths": { + "next-test-utils": ["test/lib/next-test-utils"], + "amp-test-utils": ["test/lib/amp-test-utils"], + "next-webdriver": ["test/lib/next-webdriver"] + } + }, + "include": ["test/**/*.test.ts", "test/**/*.test.tsx", "test/**/test/*"] +}