From 093288c9d79a64411355c9c5e5db76d353cd8890 Mon Sep 17 00:00:00 2001 From: Sukka Date: Thu, 12 May 2022 02:44:25 +0800 Subject: [PATCH] fix(#30300): force export 404.html (#36827) ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` The PR fixes #30300. The previous integration test case only checks if `/out/404.html` exists. However, the test passes since `/out/404.html/index.html` is being exported instead. The PR changes that by checking if a given path exists and is a file. --- packages/next/export/worker.ts | 7 ++- test/integration/export/test/index.test.js | 62 +++++++--------------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/packages/next/export/worker.ts b/packages/next/export/worker.ts index e8db5c26e467..28eab497d3bd 100644 --- a/packages/next/export/worker.ts +++ b/packages/next/export/worker.ts @@ -221,8 +221,13 @@ export default async function exportPage({ // extension of `.slug]` const pageExt = isDynamic ? '' : extname(page) const pathExt = isDynamic ? '' : extname(path) + + // force output 404.html for backwards compat + if (path === '/404.html') { + htmlFilename = path + } // Make sure page isn't a folder with a dot in the name e.g. `v1.2` - if (pageExt !== pathExt && pathExt !== '') { + else if (pageExt !== pathExt && pathExt !== '') { const isBuiltinPaths = ['/500', '/404'].some( (p) => p === path || p === path + '.html' ) diff --git a/test/integration/export/test/index.test.js b/test/integration/export/test/index.test.js index ad99c9d4882e..20216a20d6ee 100644 --- a/test/integration/export/test/index.test.js +++ b/test/integration/export/test/index.test.js @@ -20,7 +20,7 @@ import { promises } from 'fs' import dynamic from './dynamic' import apiRoutes from './api-routes' -const { access, mkdir, writeFile } = promises +const { access, mkdir, writeFile, stat } = promises const appDir = join(__dirname, '../') const outdir = join(appDir, 'out') const outNoTrailSlash = join(appDir, 'outNoTrailSlash') @@ -29,6 +29,12 @@ context.appDir = appDir const devContext = {} const nextConfig = new File(join(appDir, 'next.config.js')) +const fileExist = (path) => + access(path) + .then(() => stat(path)) + .then((stats) => (stats.isFile() ? true : false)) + .catch(() => false) + describe('Static Export', () => { it('should delete existing exported files', async () => { const tempfile = join(outdir, 'temp.txt') @@ -87,60 +93,28 @@ describe('Static Export', () => { }) it('should honor exportTrailingSlash for 404 page', async () => { - expect( - await access(join(outdir, '404/index.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) + expect(await fileExist(join(outdir, '404/index.html'))).toBe(true) // we still output 404.html for backwards compat - expect( - await access(join(outdir, '404.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) + expect(await fileExist(join(outdir, '404.html'))).toBe(true) }) it('should handle trailing slash in getStaticPaths', async () => { - expect( - await access(join(outdir, 'gssp/foo/index.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) - - expect( - await access(join(outNoTrailSlash, 'gssp/foo.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) + expect(await fileExist(join(outdir, 'gssp/foo/index.html'))).toBe(true) + + expect(await fileExist(join(outNoTrailSlash, 'gssp/foo.html'))).toBe(true) }) it('should only output 404.html without exportTrailingSlash', async () => { - expect( - await access(join(outNoTrailSlash, '404/index.html')) - .then(() => true) - .catch(() => false) - ).toBe(false) - - expect( - await access(join(outNoTrailSlash, '404.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) + expect(await fileExist(join(outNoTrailSlash, '404/index.html'))).toBe(false) + + expect(await fileExist(join(outNoTrailSlash, '404.html'))).toBe(true) }) it('should not duplicate /index with exportTrailingSlash', async () => { - expect( - await access(join(outdir, 'index/index.html')) - .then(() => true) - .catch(() => false) - ).toBe(false) - - expect( - await access(join(outdir, 'index.html')) - .then(() => true) - .catch(() => false) - ).toBe(true) + expect(await fileExist(join(outdir, 'index/index.html'))).toBe(false) + + expect(await fileExist(join(outdir, 'index.html'))).toBe(true) }) ssr(context)