Skip to content

Commit 4512e43

Browse files
committed
test(amplify-category-api-e2e-core): ensure Gen1 placeholder app + improve harness failure logging
Two Gen1 e2e harness improvements in amplify-e2e-core. Ensure Gen1 placeholder app before init: add an idempotent, best-effort run-start step that guarantees the Gen1 deprecation-bypass placeholder app (DoNotDeleteAppToBypassGen1Deprecation) and its 'test' backend environment exist in each shard's account + region before any `amplify init` runs, so the Gen1 end-of-life gate never blocks the suite and any prior cleanup-deletion is self-healed. The new ensureGen1PlaceholderApp(region) helper uses @aws-sdk/client-amplify: it paginates ListApps, creates the app via CreateApp only when missing, and creates the 'test' env via CreateBackendEnvironment only when ListBackendEnvironments shows it absent. It defaults region to process.env.CLI_REGION, relies on the ambient e2e credentials, and swallows/logs all errors so a healthy run is never broken. It is wired as a Jest globalSetup hook in both Gen1 e2e packages (amplify-e2e-tests and graphql-transformers-e2e-tests) so it runs once per shard, via standalone modules that avoid the heavy e2e-core barrel. Improve harness failure logging: initJSProjectWithProfile now emits an explicit "initJSProjectWithProfile SUCCESS" / "FAILED: <err>" instead of the misleading unconditional "...: null" on success. The nspawn run() exit handler now dumps the full captured output and the signal alongside the exit code on a non-zero exit, instead of only the last 10 lines (lastScreen) which could be empty and hid the real error. tsc of amplify-e2e-core passes.
1 parent e671e8b commit 4512e43

9 files changed

Lines changed: 110 additions & 2 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Allow people to use `amplify-category-api-e2e-core/global-setup` as a jest globalSetup.
2+
const globalSetup = require('./lib/jest-global-setup');
3+
4+
module.exports = globalSetup.default || globalSetup;

packages/amplify-e2e-core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"clean": "rimraf ./lib"
2323
},
2424
"dependencies": {
25+
"@aws-sdk/client-amplify": "~3.600.0",
2526
"@aws-sdk/client-amplifybackend": "~3.600.0",
2627
"@aws-sdk/client-appsync": "~3.600.0",
2728
"@aws-sdk/client-cloudformation": "~3.600.0",
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import {
2+
AmplifyClient,
3+
ListAppsCommand,
4+
CreateAppCommand,
5+
ListBackendEnvironmentsCommand,
6+
CreateBackendEnvironmentCommand,
7+
} from '@aws-sdk/client-amplify';
8+
9+
/**
10+
* Name of the placeholder Amplify Gen1 app that, when present in an account +
11+
* region, bypasses the Gen1 end-of-life gate during `amplify init`.
12+
*/
13+
export const GEN1_PLACEHOLDER_APP_NAME = 'DoNotDeleteAppToBypassGen1Deprecation';
14+
15+
/**
16+
* Backend environment name required on the placeholder app for the bypass to
17+
* take effect.
18+
*/
19+
export const GEN1_PLACEHOLDER_BACKEND_ENV_NAME = 'test';
20+
21+
const LIST_APPS_PAGE_SIZE = 100;
22+
23+
/**
24+
* Ensures the Gen1 deprecation-bypass placeholder app (and its `test` backend
25+
* environment) exists in the given region so the Gen1 EOL gate never blocks
26+
* `amplify init` during e2e runs, self-healing any prior cleanup deletion.
27+
*
28+
* Idempotent: the app and backend environment are created only when missing.
29+
* Never throws — all failures are logged and swallowed so an already-healthy
30+
* run is never broken by this best-effort setup step. Relies on the ambient
31+
* e2e credentials picked up by the AWS SDK default provider chain.
32+
*
33+
* @param region target AWS region; defaults to `process.env.CLI_REGION`.
34+
*/
35+
export async function ensureGen1PlaceholderApp(region: string = process.env.CLI_REGION): Promise<void> {
36+
if (!region) {
37+
console.log('⚠️ ensureGen1PlaceholderApp: no region provided (CLI_REGION unset); skipping');
38+
return;
39+
}
40+
41+
try {
42+
const client = new AmplifyClient({ region });
43+
44+
let appId: string | undefined;
45+
let nextToken: string | undefined;
46+
do {
47+
const { apps, nextToken: token } = await client.send(new ListAppsCommand({ maxResults: LIST_APPS_PAGE_SIZE, nextToken }));
48+
const existing = (apps ?? []).find((app) => app.name === GEN1_PLACEHOLDER_APP_NAME);
49+
if (existing) {
50+
appId = existing.appId;
51+
break;
52+
}
53+
nextToken = token;
54+
} while (nextToken);
55+
56+
if (!appId) {
57+
const { app } = await client.send(new CreateAppCommand({ name: GEN1_PLACEHOLDER_APP_NAME }));
58+
appId = app?.appId;
59+
console.log(`✅ ensureGen1PlaceholderApp: created placeholder app '${GEN1_PLACEHOLDER_APP_NAME}' (${appId}) in ${region}`);
60+
}
61+
62+
if (!appId) {
63+
console.log(`⚠️ ensureGen1PlaceholderApp: could not resolve placeholder appId in ${region}; skipping backend env`);
64+
return;
65+
}
66+
67+
const { backendEnvironments } = await client.send(new ListBackendEnvironmentsCommand({ appId }));
68+
const hasEnv = (backendEnvironments ?? []).some((env) => env.environmentName === GEN1_PLACEHOLDER_BACKEND_ENV_NAME);
69+
if (!hasEnv) {
70+
await client.send(new CreateBackendEnvironmentCommand({ appId, environmentName: GEN1_PLACEHOLDER_BACKEND_ENV_NAME }));
71+
console.log(
72+
`✅ ensureGen1PlaceholderApp: created backend env '${GEN1_PLACEHOLDER_BACKEND_ENV_NAME}' for placeholder app in ${region}`,
73+
);
74+
}
75+
} catch (err) {
76+
console.log(`⚠️ ensureGen1PlaceholderApp: best-effort setup failed in ${region} (continuing): ${err?.message ?? err}`);
77+
}
78+
}

packages/amplify-e2e-core/src/init/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ export * from './amplifyPull';
22
export * from './amplifyPush';
33
export * from './deleteProject';
44
export * from './initProjectHelper';
5+
export * from './ensureGen1PlaceholderApp';
56
export * from './adminUI';
67
export * from './overrideStack';

packages/amplify-e2e-core/src/init/initProjectHelper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ export function initJSProjectWithProfile(cwd: string, settings?: Partial<typeof
9999
.sendYes()
100100
.wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/)
101101
.run((err: Error) => {
102-
console.error(`Result of initJSProjectWithProfile: ${err}`);
103102
if (err) {
103+
console.error(`initJSProjectWithProfile FAILED: ${err}`);
104104
reject(err);
105105
} else {
106+
console.log('initJSProjectWithProfile SUCCESS');
106107
resolve();
107108
}
108109
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ensureGen1PlaceholderApp } from './init/ensureGen1PlaceholderApp';
2+
3+
/**
4+
* Jest `globalSetup` hook. Runs exactly once per jest invocation (i.e. once per
5+
* e2e shard) before any test file executes or any `amplify init` runs, ensuring
6+
* the Gen1 deprecation-bypass placeholder app exists in the shard's region
7+
* (`process.env.CLI_REGION`). Best-effort and idempotent — never throws.
8+
*/
9+
export default async function globalSetup(): Promise<void> {
10+
await ensureGen1PlaceholderApp(process.env.CLI_REGION);
11+
}

packages/amplify-e2e-core/src/utils/nexpect.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,18 @@ function chain(context: Context): ExecutionContext {
432432
//
433433
return onError(new Error('Command not found: ' + context.command), false);
434434
}
435+
const fullOutput = recordings.length
436+
? recordings
437+
.filter((f) => f[1] === 'o')
438+
.map((f) => f[2])
439+
.join('')
440+
: 'No output';
435441
return onError(
436-
new Error(`Process exited with non zero exit code ${code}.\n\nLast 10 lines: 👇🏽👇🏽👇🏽👇🏽\n\n\n\n\n${lastScreen}\n\n\n👆🏼👆🏼👆🏼👆🏼`),
442+
new Error(
443+
`Process exited with non zero exit code ${code}${
444+
signal ? ` (signal ${signal})` : ''
445+
}.\n\nFull output:👇🏽👇🏽👇🏽👇🏽\n\n${fullOutput}\n\n👆🏼👆🏼👆🏼👆🏼`,
446+
),
437447
false,
438448
);
439449
} else {

packages/amplify-e2e-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"jest": {
7070
"verbose": false,
7171
"preset": "ts-jest",
72+
"globalSetup": "amplify-category-api-e2e-core/global-setup",
7273
"testRunner": "amplify-category-api-e2e-core/runner",
7374
"testEnvironment": "amplify-category-api-e2e-core/environment",
7475
"transform": {

packages/graphql-transformers-e2e-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
"^axios$": "<rootDir>/../../node_modules/axios/dist/node/axios.cjs"
120120
},
121121
"testEnvironment": "../../FixJestEnvironment.js",
122+
"globalSetup": "amplify-category-api-e2e-core/global-setup",
122123
"coveragePathIgnorePatterns": [
123124
"/node_modules",
124125
"/__tests__/"

0 commit comments

Comments
 (0)