Skip to content

Commit

Permalink
feat(synthetics): node playwright 1.0 and python selenium 4.1 runtime (
Browse files Browse the repository at this point in the history
…#32245)

### Issue # (if applicable)

None

### Reason for this change

AWS Synthetics begins supporting the NodeJS Playwright runtime.

https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-cloudwatch-synthetics-playwright-runtime-canaries-nodejs/

And Python Selenium runtime v4.1 is also released.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_python_selenium.html#CloudWatch_Synthetics_runtimeversion-syn-python-selenium-4.1

### Description of changes

Add two runtimes to `Runtime` class
- SYNTHETICS_PYTHON_SELENIUM_4_1
- SYNTHETICS_NODEJS_PLAYWRIGHT_1_0

### Description of how you validated changes

Execute describe-runtime AWS CLI.
```sh
aws synthetics describe-runtime-versions --region us-east-1 | grep VersionName
            "VersionName": "syn-python-selenium-4.1",
            ...,
            "VersionName": "syn-nodejs-playwright-1.0",
            ...
```

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
badmintoncryer authored Jan 16, 2025
1 parent 1b3c22d commit d68020b
Show file tree
Hide file tree
Showing 38 changed files with 27,485 additions and 21,943 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { URL } from 'url';
import { synthetics } from '@amzn/synthetics-playwright';

const loadBlueprints = async function () {
const urls = [process.env.URL];

const browser = await synthetics.launch();
const browserContext = await browser.newContext();
let page = await synthetics.newPage(browserContext);

for (const url of urls) {
await loadUrl(page, url);
}

// Ensure browser is closed
await synthetics.close();
};

// Reset the page in-between
const resetPage = async function(page) {
try {
// Set page.goto timeout to 30 seconds, adjust as needed
// See https://playwright.dev/docs/api/class-page for page.goto options
await page.goto('about:blank', { waitUntil: 'load', timeout: 30000 });
} catch (e) {
console.error('Unable to open a blank page. ', e);
}
};

const loadUrl = async function (page, url) {
let stepName = null;
let domcontentloaded = false;

try {
stepName = new URL(url).hostname;
} catch (e) {
const errorString = `Error parsing url: ${url}. ${e}`;
log.error(errorString);
/* If we fail to parse the URL, don't emit a metric with a stepName based on it.
It may not be a legal CloudWatch metric dimension name and we may not have an alarms
setup on the malformed URL stepName. Instead, fail this step which will
show up in the logs and will fail the overall canary and alarm on the overall canary
success rate.
*/
throw e;
};

await synthetics.executeStep(stepName, async function () {
try {
/* You can customize the wait condition here.
'domcontentloaded' - consider operation to be finished when the DOMContentLoaded event is fired.
'load' - consider operation to be finished when the load event is fired.
'networkidle' - DISCOURAGED consider operation to be finished when there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead.
'commit' - consider operation to be finished when network response is received and the document started loading.
Set page.goto timeout to 30 seconds, adjust as needed
See https://playwright.dev/docs/api/class-page for page.goto options
*/
const response = await page.goto(url, { waitUntil: 'load', timeout: 30000 });
if (response) {
domcontentloaded = true;
const status = response.status();
console.log(`Response status: ${status}`);

// If the response status code is not a 2xx success code
if (status < 200 || status > 299) {
console.error(`Failed to load url: ${url}, status code: ${status}`);
throw new Error('Failed');
}
} else {
console.error(`No response returned for url: ${url}`);
throw new Error(logNoResponseString);
}
} catch (e) {
const errorString = `Error navigating to url: ${url}. ${e}`;
console.error(errorString);
throw e;
}
});

// Reset page
await resetPage(page);
};

export const handler = async (event, context) => {
return await loadBlueprints();
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { URL } from 'url';
import { synthetics } from '@amzn/synthetics-playwright';

const loadBlueprints = async function () {
const urls = [process.env.URL];

const browser = await synthetics.launch();
const browserContext = await browser.newContext();
let page = await synthetics.newPage(browserContext);

for (const url of urls) {
await loadUrl(page, url);
}

// Ensure browser is closed
await synthetics.close();
};

// Reset the page in-between
const resetPage = async function(page) {
try {
// Set page.goto timeout to 30 seconds, adjust as needed
// See https://playwright.dev/docs/api/class-page for page.goto options
await page.goto('about:blank', { waitUntil: 'load', timeout: 30000 });
} catch (e) {
console.error('Unable to open a blank page. ', e);
}
};

const loadUrl = async function (page, url) {
let stepName = null;
let domcontentloaded = false;

try {
stepName = new URL(url).hostname;
} catch (e) {
const errorString = `Error parsing url: ${url}. ${e}`;
log.error(errorString);
/* If we fail to parse the URL, don't emit a metric with a stepName based on it.
It may not be a legal CloudWatch metric dimension name and we may not have an alarms
setup on the malformed URL stepName. Instead, fail this step which will
show up in the logs and will fail the overall canary and alarm on the overall canary
success rate.
*/
throw e;
};

await synthetics.executeStep(stepName, async function () {
try {
/* You can customize the wait condition here.
'domcontentloaded' - consider operation to be finished when the DOMContentLoaded event is fired.
'load' - consider operation to be finished when the load event is fired.
'networkidle' - DISCOURAGED consider operation to be finished when there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead.
'commit' - consider operation to be finished when network response is received and the document started loading.
Set page.goto timeout to 30 seconds, adjust as needed
See https://playwright.dev/docs/api/class-page for page.goto options
*/
const response = await page.goto(url, { waitUntil: 'load', timeout: 30000 });
if (response) {
domcontentloaded = true;
const status = response.status();
console.log(`Response status: ${status}`);

// If the response status code is not a 2xx success code
if (status < 200 || status > 299) {
console.error(`Failed to load url: ${url}, status code: ${status}`);
throw new Error('Failed');
}
} else {
console.error(`No response returned for url: ${url}`);
throw new Error(logNoResponseString);
}
} catch (e) {
const errorString = `Error navigating to url: ${url}. ${e}`;
console.error(errorString);
throw e;
}
});

// Reset page
await resetPage(page);
};

export const handler = async (event, context) => {
return await loadBlueprints();
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d68020b

Please sign in to comment.