diff --git a/clients/client-cognito-identity/e2e/CognitoIdentity.ispec.ts b/clients/client-cognito-identity/e2e/CognitoIdentity.ispec.ts index fdad7741d512..6df6a0a73e33 100644 --- a/clients/client-cognito-identity/e2e/CognitoIdentity.ispec.ts +++ b/clients/client-cognito-identity/e2e/CognitoIdentity.ispec.ts @@ -7,7 +7,7 @@ import { expect } from "chai"; import { CognitoIdentity } from "../index"; // There will be default values of defaultRegion, credentials, and isBrowser variable in browser tests. // Define the values for Node.js tests -const region: string | undefined = (globalThis as any).defaultRegion || undefined; +const region: string | undefined = (globalThis as any).defaultRegion || process?.env?.AWS_SMOKE_TEST_REGION; const IdentityPoolId = (globalThis as any)?.window?.__env__?.AWS_SMOKE_TEST_IDENTITY_POOL_ID || process?.env?.AWS_SMOKE_TEST_IDENTITY_POOL_ID; diff --git a/clients/client-s3/e2e/S3.ispec.ts b/clients/client-s3/e2e/S3.ispec.ts index 271eb80eedb7..979ebe0a4d38 100644 --- a/clients/client-s3/e2e/S3.ispec.ts +++ b/clients/client-s3/e2e/S3.ispec.ts @@ -12,7 +12,7 @@ chai.use(chaiAsPromised); const { expect } = chai; // There will be default values of defaultRegion, credentials, and isBrowser variable in browser tests. // Define the values for Node.js tests -const region: string | undefined = (globalThis as any).defaultRegion || undefined; +const region: string | undefined = (globalThis as any).defaultRegion || process?.env?.AWS_SMOKE_TEST_REGION; const credentials: Credentials | undefined = (globalThis as any).credentials || undefined; const isBrowser: boolean | undefined = (globalThis as any).isBrowser || false; const Bucket = (globalThis as any)?.window?.__env__?.AWS_SMOKE_TEST_BUCKET || process?.env?.AWS_SMOKE_TEST_BUCKET; diff --git a/package.json b/package.json index 1c1ca5694b44..76f5e7c0c356 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "test:integration-legacy": "cucumber-js --fail-fast", "test:integration": "jest --config jest.config.integ.js --passWithNoTests", "test:protocols": "yarn build:protocols && lerna run test --scope '@aws-sdk/aws-*'", + "test:e2e": "node ./tests/e2e/index.js", "local-publish": "node ./scripts/verdaccio-publish/index.js" }, "repository": { diff --git a/tests/e2e/get-integ-test-resources.js b/tests/e2e/get-integ-test-resources.js new file mode 100644 index 000000000000..598dc1e162c6 --- /dev/null +++ b/tests/e2e/get-integ-test-resources.js @@ -0,0 +1,23 @@ +const { CloudFormationClient, DescribeStackResourcesCommand } = require("../../clients/client-cloudformation"); + +exports.getIntegTestResources = async () => { + const client = new CloudFormationClient({}); + const region = await client.config.region(); + + const { StackResources: stackResources } = await client.send( + new DescribeStackResourcesCommand({ StackName: "IntegTestResourcesStack" }) + ); + + const identityPoolId = stackResources.filter((resource) => resource.ResourceType === "AWS::Cognito::IdentityPool")[0] + .PhysicalResourceId; + + const bucketName = stackResources.filter( + (resource) => resource.ResourceType === "AWS::S3::Bucket" && resource.LogicalResourceId.indexOf("IntegTest") === 0 + )[0].PhysicalResourceId; + + return { + AWS_SMOKE_TEST_REGION: region, + AWS_SMOKE_TEST_IDENTITY_POOL_ID: identityPoolId, + AWS_SMOKE_TEST_BUCKET: bucketName, + }; +}; diff --git a/tests/e2e/index.js b/tests/e2e/index.js new file mode 100644 index 000000000000..1e2c4dd01aca --- /dev/null +++ b/tests/e2e/index.js @@ -0,0 +1,13 @@ +const { getIntegTestResources } = require("./get-integ-test-resources"); +const { runE2ETests } = require("./run-e2e-tests"); + +const run = async () => { + try { + const integTestResourcesEnv = await getIntegTestResources(); + await runE2ETests(integTestResourcesEnv); + } catch (e) { + process.exit(1); + } +}; + +run(); diff --git a/tests/e2e/run-e2e-tests.js b/tests/e2e/run-e2e-tests.js new file mode 100644 index 000000000000..f915b7febf7f --- /dev/null +++ b/tests/e2e/run-e2e-tests.js @@ -0,0 +1,49 @@ +const { execSync, spawn } = require("child_process"); +const { join } = require("path"); +const { readFileSync, existsSync } = require("fs"); +const { spawnPromise } = require("./spawn-promise"); + +const hasE2Etest = (packagePath) => { + const path = join(packagePath, "package.json"); + if (!existsSync(path)) return false; + const pkgJson = JSON.parse(readFileSync(path).toString()); + return Boolean(pkgJson.scripts["test:e2e"]); +}; + +exports.runE2ETests = async (resourcesEnv) => { + /** + * Example output: + /path/to/package:@aws-sdk/client-accessanalyzer:1.0.0-gamma.3 + /path/to/package:@aws-sdk/client-acm-pca:1.0.0-gamma.3 + /path/to/package:@aws-sdk/client-acm:1.0.0-gamma.3 + */ + const changedPackagesRecord = execSync( + "./node_modules/.bin/lerna changed --all --parseable --long --loglevel silent" + ); + // Get array for changed package's path + const changedPackages = changedPackagesRecord + .toString() + .split("\n") + .map((record) => record.split(":").slice(0, 2)); + const packagesToTest = changedPackages.filter((changedPackage) => hasE2Etest(changedPackage[0])); + console.log(`packages to run e2e test: +${packagesToTest.map((package) => package[0]).join("\n")}`); + await spawnPromise( + "./node_modules/.bin/lerna", + [ + "run", + "test:e2e", + "--scope", + `'{${packagesToTest.map((package) => package[1]).join(",")}}'`, // https://github.com/lerna/lerna/issues/1846#issuecomment-451172783 + "--concurrency", + "1", + ], + { + env: { + ...process.env, + ...resourcesEnv, + }, + stdio: "inherit", + } + ); +}; diff --git a/tests/e2e/spawn-promise.js b/tests/e2e/spawn-promise.js new file mode 100644 index 000000000000..3bfcd83851df --- /dev/null +++ b/tests/e2e/spawn-promise.js @@ -0,0 +1,17 @@ +const { spawn } = require("child_process"); + +exports.spawnPromise = (command, options, spawnOptions) => + new Promise((resolve, reject) => { + const ps = spawn(command, options, { + stdio: "inherit", + ...spawnOptions, + }); + ps.on("error", reject); + ps.on("exit", (code) => { + if (code !== 0) { + reject(new Error(`Unexpected exit code [${code}]`)); + } else { + resolve(); + } + }); + });