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
This commit is contained in:
parent
6072afc83a
commit
005b13f1ac
99 changed files with 202 additions and 214 deletions
2
.github/workflows/build_test_deploy.yml
vendored
2
.github/workflows/build_test_deploy.yml
vendored
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
testMatch: ['**/*.test.js'],
|
||||
testMatch: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'],
|
||||
verbose: true,
|
||||
rootDir: 'test',
|
||||
modulePaths: ['<rootDir>/lib'],
|
||||
|
|
14
package.json
14
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 .",
|
||||
|
|
73
run-tests.js
73
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) {
|
||||
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) {
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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";
|
|
@ -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 = () => (
|
|
@ -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',
|
|
@ -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 = () => (
|
|
@ -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'
|
|
@ -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';
|
|
@ -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: [
|
||||
{
|
|
@ -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: [
|
||||
{
|
|
@ -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: [
|
||||
{
|
|
@ -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')],
|
||||
},
|
|
@ -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';
|
|
@ -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";
|
|
@ -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: [
|
||||
{
|
|
@ -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";
|
|
@ -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';
|
|
@ -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";
|
|
@ -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: [
|
||||
`
|
|
@ -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';
|
|
@ -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', () => {
|
|
@ -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')
|
||||
})
|
||||
})
|
|
@ -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')
|
||||
})
|
||||
})
|
|
@ -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', () => {
|
BIN
test/unit/image-optimizer/images/animated.webp
Normal file
BIN
test/unit/image-optimizer/images/animated.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
test/unit/image-optimizer/images/test.jpg
Normal file
BIN
test/unit/image-optimizer/images/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
BIN
test/unit/image-optimizer/images/test.png
Normal file
BIN
test/unit/image-optimizer/images/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
13
test/unit/image-optimizer/images/test.svg
Normal file
13
test/unit/image-optimizer/images/test.svg
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="400" height="400" viewBox="0 0 400 400"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M0 2000 l0 -2000 2000 0 2000 0 0 2000 0 2000 -2000 0 -2000 0 0
|
||||
-2000z m2401 118 l396 -693 -398 -3 c-220 -1 -578 -1 -798 0 l-398 3 396 693
|
||||
c217 380 398 692 401 692 3 0 184 -312 401 -692z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 603 B |
|
@ -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))
|
|
@ -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')
|
|
@ -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.'
|
||||
)
|
|
@ -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<string>((resolve, reject) => {
|
||||
function callback(err, content) {
|
||||
if (err) {
|
||||
reject(err)
|
|
@ -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', () => {
|
|
@ -9,7 +9,7 @@ describe('Rendering next/head', () => {
|
|||
React.createElement(
|
||||
React.Fragment,
|
||||
{},
|
||||
React.createElement(Head, {}),
|
||||
React.createElement(Head),
|
||||
React.createElement('p', {}, 'hello world')
|
||||
)
|
||||
)
|
|
@ -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', () => {
|
|
@ -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 () => {
|
|
@ -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)
|
||||
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
@ -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/*"]
|
||||
}
|
Loading…
Reference in a new issue