Skip to content

Commit 4a8401a

Browse files
committed
progress - e2e tests
1 parent c6626f9 commit 4a8401a

File tree

2 files changed

+330
-20
lines changed

2 files changed

+330
-20
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import * as assert from "assert";
2+
import { posix } from "path";
3+
import fsExtra from "fs-extra";
4+
5+
const host = process.env.HOST;
6+
if (!host) {
7+
throw new Error("HOST environment variable expected");
8+
}
9+
10+
const scenario = process.env.SCENARIO;
11+
if (!scenario) {
12+
throw new Error("SCENARIO environment variable expected");
13+
}
14+
15+
const runId = process.env.RUN_ID;
16+
if (!runId) {
17+
throw new Error("RUN_ID environment variable expected");
18+
}
19+
20+
describe("next.config override", () => {
21+
it("should have images optimization disabled", async () => {
22+
const serverFiles = await fsExtra.readJson(
23+
`${process.cwd()}/e2e/runs/${runId}/.next/standalone/.next/required-server-files.json`,
24+
);
25+
console.log(`serverFiles: ${JSON.stringify(serverFiles)}`);
26+
const config = serverFiles.config;
27+
28+
// Verify that images.unoptimized is set to true
29+
assert.ok(config.images, "Config should have images property");
30+
assert.strictEqual(
31+
config.images.unoptimized,
32+
true,
33+
"Images should have unoptimized set to true",
34+
);
35+
});
36+
37+
// it("should preserve user config settings", async () => {
38+
// // This test checks if the user's original config settings are preserved
39+
// // We'll check for the custom header that was set in the next.config
40+
// const response = await fetch(posix.join(host, "/"));
41+
// assert.ok(response.ok);
42+
43+
// // Check for the custom header that was set in the next.config
44+
// if (scenario.includes("with-js-config")) {
45+
// assert.equal(response.headers.get("x-custom-header") ?? "", "js-config-value");
46+
// } else if (scenario.includes("with-ts-config")) {
47+
// assert.equal(response.headers.get("x-custom-header") ?? "", "ts-config-value");
48+
// } else if (scenario.includes("with-mjs-config")) {
49+
// assert.equal(response.headers.get("x-custom-header") ?? "", "mjs-config-value");
50+
// } else if (scenario.includes("with-complex-config")) {
51+
// assert.equal(response.headers.get("x-custom-header") ?? "", "complex-config-value");
52+
// }
53+
// });
54+
55+
// it("should handle function-style config correctly", async () => {
56+
// // Only run this test for scenarios with function-style config
57+
// if (!scenario.includes("function-style")) {
58+
// this.skip();
59+
// return;
60+
// }
61+
62+
// // Check for the custom header that indicates function-style config was processed correctly
63+
// const response = await fetch(posix.join(host, "/"));
64+
// assert.ok(response.ok);
65+
// assert.equal(response.headers.get("x-config-type") ?? "", "function");
66+
// });
67+
68+
// it("should handle object-style config correctly", async () => {
69+
// // Only run this test for scenarios with object-style config
70+
// if (
71+
// !scenario.includes("object-style") &&
72+
// !scenario.includes("with-complex-config") &&
73+
// !scenario.includes("with-empty-config")
74+
// ) {
75+
// this.skip();
76+
// return;
77+
// }
78+
79+
// // Check for the custom header that indicates object-style config was processed correctly
80+
// const response = await fetch(posix.join(host, "/"));
81+
// assert.ok(response.ok);
82+
83+
// // Empty config doesn't set this header
84+
// if (!scenario.includes("with-empty-config")) {
85+
// assert.equal(response.headers.get("x-config-type") ?? "", "object");
86+
// }
87+
// });
88+
89+
// it("should handle empty config correctly", async () => {
90+
// // Only run this test for the empty config scenario
91+
// if (!scenario.includes("with-empty-config")) {
92+
// this.skip();
93+
// return;
94+
// }
95+
96+
// // Just check that the page loads successfully
97+
// const response = await fetch(posix.join(host, "/"));
98+
// assert.ok(response.ok);
99+
// });
100+
101+
// it("should verify original config file was preserved", async () => {
102+
// // This test verifies that the original config file was preserved
103+
// // We'll check the file system to make sure the original config file exists
104+
// let originalConfigExists = false;
105+
106+
// if (scenario.includes("with-js-config")) {
107+
// originalConfigExists = await fsExtra.pathExists("next.config.original.js");
108+
// } else if (scenario.includes("with-ts-config")) {
109+
// originalConfigExists = await fsExtra.pathExists("next.config.original.ts");
110+
// } else if (scenario.includes("with-mjs-config")) {
111+
// originalConfigExists = await fsExtra.pathExists("next.config.original.mjs");
112+
// } else if (
113+
// scenario.includes("with-empty-config") ||
114+
// scenario.includes("with-complex-config") ||
115+
// scenario.includes("with-error-handling")
116+
// ) {
117+
// originalConfigExists = await fsExtra.pathExists("next.config.original.js");
118+
// }
119+
120+
// assert.ok(originalConfigExists, "Original config file should be preserved");
121+
// });
122+
123+
// it("should handle error gracefully when config file has syntax errors", async () => {
124+
// // Only run this test for the error handling scenario
125+
// if (!scenario.includes("with-error-handling")) {
126+
// this.skip();
127+
// return;
128+
// }
129+
130+
// // The build should have succeeded despite the invalid config file
131+
// // because we started with a valid config
132+
// const response = await fetch(posix.join(host, "/"));
133+
// assert.ok(response.ok);
134+
135+
// // Check if the invalid config file exists
136+
// const invalidConfigExists = await fsExtra.pathExists("next.config.invalid.js");
137+
// assert.ok(invalidConfigExists, "Invalid config file should exist");
138+
// });
139+
140+
// it("should verify the generated config file has the correct format", async () => {
141+
// // Skip for error handling scenario
142+
// if (scenario.includes("with-error-handling")) {
143+
// this.skip();
144+
// return;
145+
// }
146+
147+
// let configPath = "";
148+
149+
// if (scenario.includes("with-js-config")) {
150+
// configPath = "next.config.js";
151+
// } else if (scenario.includes("with-ts-config")) {
152+
// configPath = "next.config.ts";
153+
// } else if (scenario.includes("with-mjs-config")) {
154+
// configPath = "next.config.mjs";
155+
// } else if (scenario.includes("with-empty-config") || scenario.includes("with-complex-config")) {
156+
// configPath = "next.config.js";
157+
// }
158+
159+
// // Check if the generated config file exists
160+
// const configExists = await fsExtra.pathExists(configPath);
161+
// assert.ok(configExists, "Generated config file should exist");
162+
163+
// // Read the config file content
164+
// const configContent = await fsExtra.readFile(configPath, "utf-8");
165+
166+
// // Verify that the config file contains the unoptimized: true setting
167+
// assert.ok(configContent.includes("unoptimized: true"), "Config should have unoptimized: true");
168+
169+
// // Verify that the config file imports the original config
170+
// if (
171+
// scenario.includes("with-js-config") ||
172+
// scenario.includes("with-empty-config") ||
173+
// scenario.includes("with-complex-config")
174+
// ) {
175+
// assert.ok(
176+
// configContent.includes("require('./next.config.original.js')"),
177+
// "Config should import the original JS config",
178+
// );
179+
// } else if (scenario.includes("with-ts-config")) {
180+
// assert.ok(
181+
// configContent.includes("import originalConfig from './next.config.original'"),
182+
// "Config should import the original TS config",
183+
// );
184+
// } else if (scenario.includes("with-mjs-config")) {
185+
// assert.ok(
186+
// configContent.includes("import originalConfig from './next.config.original.mjs'"),
187+
// "Config should import the original MJS config",
188+
// );
189+
// }
190+
// });
191+
});

packages/@apphosting/adapter-nextjs/e2e/run-local.ts

Lines changed: 139 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,151 @@ interface Scenario {
2020
}
2121

2222
const scenarios: Scenario[] = [
23-
{
24-
name: "basic",
25-
// No setup needed for basic scenario
26-
tests: ["app.spec.ts"],
27-
},
28-
{
29-
name: "with-middleware",
30-
setup: async (cwd: string) => {
31-
// Create a middleware.ts file
32-
const middlewareContent = `
33-
import type { NextRequest } from 'next/server'
23+
// {
24+
// name: "basic",
25+
// // No setup needed for basic scenario
26+
// tests: ["app.spec.ts"],
27+
// },
28+
// {
29+
// name: "with-middleware",
30+
// setup: async (cwd: string) => {
31+
// // Create a middleware.ts file
32+
// const middlewareContent = `
33+
// import type { NextRequest } from 'next/server'
34+
35+
// export function middleware(request: NextRequest) {
36+
// // This is a simple middleware that doesn't modify the request
37+
// console.log('Middleware executed', request.nextUrl.pathname);
38+
// }
3439

35-
export function middleware(request: NextRequest) {
36-
// This is a simple middleware that doesn't modify the request
37-
console.log('Middleware executed', request.nextUrl.pathname);
38-
}
40+
// export const config = {
41+
// matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)',
42+
// };
43+
// `;
3944

40-
export const config = {
41-
matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)',
45+
// await fsExtra.writeFile(join(cwd, "src", "middleware.ts"), middlewareContent);
46+
// console.log(`Created middleware.ts file`);
47+
// },
48+
// tests: ["middleware.spec.ts"], // Only run middleware-specific tests
49+
// },
50+
// New scenarios for testing Next.js config override behavior
51+
{
52+
name: "with-js-config-object-style",
53+
setup: async (cwd: string) => {
54+
// Create a next.config.js file with object-style config
55+
const configContent = `
56+
/** @type {import('next').NextConfig} */
57+
const nextConfig = {
58+
reactStrictMode: true,
59+
async headers() {
60+
return [
61+
{
62+
source: '/:path*',
63+
headers: [
64+
{
65+
key: 'x-custom-header',
66+
value: 'js-config-value',
67+
},
68+
{
69+
key: 'x-config-type',
70+
value: 'object',
71+
},
72+
],
73+
},
74+
];
75+
},
4276
};
77+
78+
module.exports = nextConfig;
4379
`;
4480

45-
await fsExtra.writeFile(join(cwd, "src", "middleware.ts"), middlewareContent);
46-
console.log(`Created middleware.ts file`);
81+
await fsExtra.writeFile(join(cwd, "next.config.js"), configContent);
82+
console.log(`Created next.config.js file with object-style config`);
4783
},
48-
tests: ["middleware.spec.ts"], // Only run middleware-specific tests
84+
tests: ["config-override.spec.ts"],
4985
},
86+
// {
87+
// name: "with-js-config-object-style",
88+
// setup: async (cwd: string) => {
89+
// // Create a next.config.js file with object-style config
90+
// const configContent = `
91+
// /** @type {import('next').NextConfig} */
92+
// const nextConfig = {
93+
// reactStrictMode: true,
94+
// async headers() {
95+
// return [
96+
// {
97+
// source: '/:path*',
98+
// headers: [
99+
// {
100+
// key: 'x-custom-header',
101+
// value: 'js-config-value',
102+
// },
103+
// {
104+
// key: 'x-config-type',
105+
// value: 'object',
106+
// },
107+
// ],
108+
// },
109+
// ];
110+
// },
111+
// // This should be overridden by the adapter
112+
// images: {
113+
// unoptimized: false,
114+
// domains: ['example.com'],
115+
// },
116+
// };
117+
118+
// module.exports = nextConfig;
119+
// `;
120+
121+
// await fsExtra.writeFile(join(cwd, "next.config.js"), configContent);
122+
// console.log(`Created next.config.js file with object-style config`);
123+
// },
124+
// tests: ["config-override.spec.ts"],
125+
// },
126+
// {
127+
// name: "with-js-config-function-style",
128+
// setup: async (cwd: string) => {
129+
// // Create a next.config.js file with function-style config
130+
// const configContent = `
131+
// /** @type {import('next').NextConfig} */
132+
// const nextConfig = (phase, { defaultConfig }) => {
133+
// return {
134+
// reactStrictMode: true,
135+
// async headers() {
136+
// return [
137+
// {
138+
// source: '/:path*',
139+
// headers: [
140+
// {
141+
// key: 'x-custom-header',
142+
// value: 'js-config-value',
143+
// },
144+
// {
145+
// key: 'x-config-type',
146+
// value: 'function',
147+
// },
148+
// ],
149+
// },
150+
// ];
151+
// },
152+
// // This should be overridden by the adapter
153+
// images: {
154+
// unoptimized: false,
155+
// domains: ['example.com'],
156+
// },
157+
// };
158+
// };
159+
160+
// module.exports = nextConfig;
161+
// `;
162+
163+
// await fsExtra.writeFile(join(cwd, "next.config.js"), configContent);
164+
// console.log(`Created next.config.js file with function-style config`);
165+
// },
166+
// tests: ["config-override.spec.ts"],
167+
// },
50168
];
51169

52170
const errors: any[] = [];
@@ -170,6 +288,7 @@ for (const scenario of scenarios) {
170288
...process.env,
171289
HOST: host,
172290
SCENARIO: scenario.name,
291+
RUN_ID: runId,
173292
},
174293
}).finally(() => {
175294
run.stdin.end();

0 commit comments

Comments
 (0)