Fix failing tests, update page component handler to exclude 404 pages on retries
This commit is contained in:
+3
-7
@@ -63,14 +63,12 @@ export default async function grabPageComponent(params) {
|
||||
// Only retry transient failures: if the last rebuild failed
|
||||
// (BUNEXT_BUILD_FAILED), the file is broken and more rebuilds
|
||||
// will just repeat the same error.
|
||||
while (retries < MAX_RETRIES &&
|
||||
!global.BUNEXT_BUILD_FAILED) {
|
||||
while (retries < MAX_RETRIES && !global.BUNEXT_BUILD_FAILED) {
|
||||
await fullRebuild({
|
||||
msg: `Retrying Bundle map for file \`${relative_file_path}\``,
|
||||
});
|
||||
await Bun.sleep(1000);
|
||||
bundledMap =
|
||||
global.BUNEXT_BUNDLER_CTX_MAP[relative_file_path];
|
||||
bundledMap = global.BUNEXT_BUNDLER_CTX_MAP[relative_file_path];
|
||||
if (bundledMap?.path)
|
||||
break;
|
||||
retries++;
|
||||
@@ -122,9 +120,7 @@ export default async function grabPageComponent(params) {
|
||||
const is404 = error instanceof NotFoundError ||
|
||||
error?.name === "NotFoundError" ||
|
||||
error?.status === 404;
|
||||
if (!params.retry && !params.no_retry && is_dev) {
|
||||
// Skip the retry cascade when the last rebuild failed: the error
|
||||
// is persistent and more rebuilds would repeat it endlessly.
|
||||
if (!params.retry && !params.no_retry && is_dev && !is404) {
|
||||
while (!global.BUNEXT_BUILD_FAILED &&
|
||||
global.BUNEXT_REBUILD_RETRIES < 2) {
|
||||
global.BUNEXT_REBUILD_RETRIES =
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moduletrace/bunext",
|
||||
"version": "1.1.15",
|
||||
"version": "1.1.16",
|
||||
"main": "dist/index.js",
|
||||
"module": "index.ts",
|
||||
"dependencies": {
|
||||
|
||||
@@ -131,7 +131,6 @@ describe("E2E Integration", () => {
|
||||
if (server) {
|
||||
server.stop(true);
|
||||
}
|
||||
global.BUNEXT_SERVER = undefined;
|
||||
|
||||
process.chdir(originalCwd);
|
||||
|
||||
@@ -142,6 +141,18 @@ describe("E2E Integration", () => {
|
||||
delete process.env.PORT;
|
||||
}
|
||||
|
||||
// Reset globals this file mutated so later test files (which share
|
||||
// the process when bun runs un-isolated) never see fixture state.
|
||||
global.BUNEXT_DIR_NAMES = undefined as any;
|
||||
global.BUNEXT_CONFIG = undefined as any;
|
||||
global.BUNEXT_CONSTANTS = undefined as any;
|
||||
global.BUNEXT_SERVER = undefined;
|
||||
global.BUNEXT_ROUTER = undefined as any;
|
||||
global.BUNEXT_BUNDLER_CTX_MAP = undefined;
|
||||
global.BUNEXT_SSR_BUNDLER_CTX_MAP = undefined as any;
|
||||
global.BUNEXT_HMR_CONTROLLERS = [];
|
||||
global.BUNEXT_REACT_DOM_MODULE_CACHE = new Map<string, any>();
|
||||
|
||||
// Remove generated artifacts from the fixture
|
||||
const dotBunext = path.join(fixtureDir, ".bunext");
|
||||
if (fs.existsSync(dotBunext)) {
|
||||
|
||||
@@ -41,6 +41,7 @@ describe("grabPageComponent", () => {
|
||||
req: new Request("http://localhost:3000/unknown-foo-bar123"),
|
||||
});
|
||||
|
||||
console.log("DEBUG-404:", res instanceof Response ? "Response" : JSON.stringify(res));
|
||||
expect(res.serverRes?.response_options?.status).toBe(404);
|
||||
expect(log.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test";
|
||||
import { describe, expect, test, beforeEach, afterEach } from "bun:test";
|
||||
|
||||
const grabPageComponent = mock(async () => ({
|
||||
serverRes: { props: { ok: true } },
|
||||
}));
|
||||
|
||||
mock.module(
|
||||
"../../../functions/server/web-pages/grab-page-component",
|
||||
() => ({
|
||||
default: grabPageComponent,
|
||||
}),
|
||||
);
|
||||
|
||||
const { default: serverPostBuildFn } = await import(
|
||||
"../../../functions/server/server-post-build-fn"
|
||||
);
|
||||
// NOTE: this file runs the REAL grabPageComponent (no module mock). The
|
||||
// callers use `return_server_res_only` + `no_retry`, so no bundling or
|
||||
// rebuilds happen as long as the fake router + artifact map are set up.
|
||||
import serverPostBuildFn from "../../../functions/server/server-post-build-fn";
|
||||
|
||||
function makeController(page_url: string, target_map?: { local_path: string }) {
|
||||
const enqueued: string[] = [];
|
||||
@@ -31,30 +21,41 @@ function makeController(page_url: string, target_map?: { local_path: string }) {
|
||||
|
||||
describe("server-post-build-fn", () => {
|
||||
beforeEach(() => {
|
||||
grabPageComponent.mockClear();
|
||||
global.BUNEXT_ROUTER = {
|
||||
match: (path: string) => {
|
||||
if (path === "/about")
|
||||
return { filePath: "/pages/about.tsx" };
|
||||
if (path === "/new-page")
|
||||
return { filePath: "/pages/new-page.tsx" };
|
||||
return null;
|
||||
},
|
||||
} as any;
|
||||
global.BUNEXT_BUNDLER_CTX_MAP = {
|
||||
"/pages/about.tsx": {
|
||||
local_path: "/pages/about.tsx",
|
||||
"pages/about.tsx": {
|
||||
local_path: "pages/about.tsx",
|
||||
path: "pages/about.js",
|
||||
} as any,
|
||||
"/pages/404.tsx": {
|
||||
local_path: "/pages/404.tsx",
|
||||
"pages/404.tsx": {
|
||||
local_path: "pages/404.tsx",
|
||||
path: "pages/404.js",
|
||||
} as any,
|
||||
};
|
||||
global.BUNEXT_HMR_CONTROLLERS = [];
|
||||
global.BUNEXT_ROOT_FILE_UPDATED = false;
|
||||
global.BUNEXT_IS_404_PAGE = false;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.BUNEXT_ROUTER = undefined as any;
|
||||
global.BUNEXT_BUNDLER_CTX_MAP = undefined as any;
|
||||
global.BUNEXT_HMR_CONTROLLERS = [];
|
||||
global.BUNEXT_ROOT_FILE_UPDATED = false;
|
||||
global.BUNEXT_IS_404_PAGE = false;
|
||||
});
|
||||
|
||||
test("soft-updates a normal page controller", async () => {
|
||||
const c = makeController("http://localhost/about", {
|
||||
local_path: "/pages/about.tsx",
|
||||
local_path: "pages/about.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [c as any];
|
||||
|
||||
@@ -63,13 +64,12 @@ describe("server-post-build-fn", () => {
|
||||
expect(c.enqueued.length).toBe(1);
|
||||
expect(c.enqueued[0]).toContain("event: update");
|
||||
expect(c.enqueued[0]).not.toContain('"reload":true');
|
||||
expect(c.enqueued[0]).toContain("/pages/about.tsx");
|
||||
expect(grabPageComponent).toHaveBeenCalled();
|
||||
expect(c.enqueued[0]).toContain("pages/about.tsx");
|
||||
});
|
||||
|
||||
test("soft-updates unmatched URL via custom 404 artifact", async () => {
|
||||
const c = makeController("http://localhost/missing", {
|
||||
local_path: "/pages/404.tsx",
|
||||
local_path: "pages/404.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [c as any];
|
||||
|
||||
@@ -77,13 +77,12 @@ describe("server-post-build-fn", () => {
|
||||
|
||||
expect(c.enqueued.length).toBe(1);
|
||||
expect(c.enqueued[0]).not.toContain('"reload":true');
|
||||
expect(c.enqueued[0]).toContain("/pages/404.tsx");
|
||||
expect(grabPageComponent).toHaveBeenCalled();
|
||||
expect(c.enqueued[0]).toContain("pages/404.tsx");
|
||||
});
|
||||
|
||||
test("full-reloads when the controller's target artifact is missing from the map", async () => {
|
||||
const c = makeController("http://localhost/gone", {
|
||||
local_path: "/pages/removed.tsx",
|
||||
local_path: "pages/removed.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [c as any];
|
||||
|
||||
@@ -91,15 +90,14 @@ describe("server-post-build-fn", () => {
|
||||
|
||||
expect(c.enqueued.length).toBe(1);
|
||||
expect(c.enqueued[0]).toContain('"reload":true');
|
||||
expect(grabPageComponent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("full-reloads every controller when reload_all_controllers is set", async () => {
|
||||
const c1 = makeController("http://localhost/about", {
|
||||
local_path: "/pages/about.tsx",
|
||||
local_path: "pages/about.tsx",
|
||||
});
|
||||
const c2 = makeController("http://localhost/missing", {
|
||||
local_path: "/pages/404.tsx",
|
||||
local_path: "pages/404.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [c1 as any, c2 as any];
|
||||
|
||||
@@ -109,12 +107,11 @@ describe("server-post-build-fn", () => {
|
||||
expect(c1.enqueued[0]).toContain('"reload":true');
|
||||
expect(c2.enqueued.length).toBe(1);
|
||||
expect(c2.enqueued[0]).toContain('"reload":true');
|
||||
expect(grabPageComponent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("enqueues reload when the root file changed and resets the flag", async () => {
|
||||
const c = makeController("http://localhost/about", {
|
||||
local_path: "/pages/about.tsx",
|
||||
local_path: "pages/about.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [c as any];
|
||||
global.BUNEXT_ROOT_FILE_UPDATED = true;
|
||||
@@ -133,19 +130,18 @@ describe("server-post-build-fn", () => {
|
||||
await serverPostBuildFn();
|
||||
|
||||
expect(c.enqueued.length).toBe(0);
|
||||
expect(grabPageComponent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("only touches controllers whose page is in changed_pages", async () => {
|
||||
const changed = makeController("http://localhost/about", {
|
||||
local_path: "/pages/about.tsx",
|
||||
local_path: "pages/about.tsx",
|
||||
});
|
||||
const untouched = makeController("http://localhost/missing", {
|
||||
local_path: "/pages/404.tsx",
|
||||
local_path: "pages/404.tsx",
|
||||
});
|
||||
global.BUNEXT_HMR_CONTROLLERS = [changed as any, untouched as any];
|
||||
|
||||
await serverPostBuildFn({ changed_pages: ["/pages/about.tsx"] });
|
||||
await serverPostBuildFn({ changed_pages: ["pages/about.tsx"] });
|
||||
|
||||
expect(changed.enqueued.length).toBe(1);
|
||||
expect(untouched.enqueued.length).toBe(0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, mock, afterEach } from "bun:test";
|
||||
import { describe, expect, test, mock, afterEach, afterAll } from "bun:test";
|
||||
import startServer from "../../../../src/functions/server/start-server";
|
||||
import { log } from "../../../../src/utils/log";
|
||||
|
||||
@@ -29,6 +29,12 @@ describe("startServer", () => {
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Prevent the module mocks (log, grab-config, grab-app-port) from
|
||||
// leaking into other test files sharing this process.
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
test("starts the server and assigns to global.BUNEXT_SERVER", async () => {
|
||||
global.BUNEXT_CONFIG = { development: true };
|
||||
|
||||
|
||||
@@ -115,16 +115,12 @@ export default async function grabPageComponent(
|
||||
// Only retry transient failures: if the last rebuild failed
|
||||
// (BUNEXT_BUILD_FAILED), the file is broken and more rebuilds
|
||||
// will just repeat the same error.
|
||||
while (
|
||||
retries < MAX_RETRIES &&
|
||||
!global.BUNEXT_BUILD_FAILED
|
||||
) {
|
||||
while (retries < MAX_RETRIES && !global.BUNEXT_BUILD_FAILED) {
|
||||
await fullRebuild({
|
||||
msg: `Retrying Bundle map for file \`${relative_file_path}\``,
|
||||
});
|
||||
await Bun.sleep(1000);
|
||||
bundledMap =
|
||||
global.BUNEXT_BUNDLER_CTX_MAP[relative_file_path];
|
||||
bundledMap = global.BUNEXT_BUNDLER_CTX_MAP[relative_file_path];
|
||||
if (bundledMap?.path) break;
|
||||
retries++;
|
||||
}
|
||||
@@ -185,9 +181,7 @@ export default async function grabPageComponent(
|
||||
error?.name === "NotFoundError" ||
|
||||
error?.status === 404;
|
||||
|
||||
if (!params.retry && !params.no_retry && is_dev) {
|
||||
// Skip the retry cascade when the last rebuild failed: the error
|
||||
// is persistent and more rebuilds would repeat it endlessly.
|
||||
if (!params.retry && !params.no_retry && is_dev && !is404) {
|
||||
while (
|
||||
!global.BUNEXT_BUILD_FAILED &&
|
||||
global.BUNEXT_REBUILD_RETRIES < 2
|
||||
|
||||
Reference in New Issue
Block a user