

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Playwright 執行時期撰寫 Node.js Canary 指令碼
<a name="Synthetics_WritingCanary_Nodejs_Playwright"></a>

**Topics**
+ [為 Playwright 執行時期封裝 Node.js Canary 檔案](#Synthetics_canary_Nodejs_Playwright_package)
+ [變更現有 Playwright 指令碼以用作 CloudWatch Synthetics Canary](#CloudWatch_Synthetics_canary_edit_Playwright_script)
+ [CloudWatch Synthetics 組態](#Synthetics_canary_configure_Playwright_script)

## 為 Playwright 執行時期封裝 Node.js Canary 檔案
<a name="Synthetics_canary_Nodejs_Playwright_package"></a>

 Canary 指令碼由 `.js` (CommonJS 語法) 或 `.mjs`(ES 語法) 檔案組成，其中包含您的 Synthetics 處理常式程式碼，以及程式碼所依賴的任何其他套件和模組。以 ES (ECMAScript) 格式建立的指令碼應使用 .mjs 作為副檔名，或包含具有「類型」：「模組」欄位集的 package.json 檔案。與 Node.js Puppeteer 等其他執行時期不同，您不需要將指令碼儲存在特定的資料夾結構中。可以直接封裝指令碼。使用您慣用的 `zip` 公用程式建立 `.zip` 檔案，並將處理常式檔案放在根目錄下。如果您的 Canary 指令碼仰賴 Synthetics 執行時期中未包含的其他套件或模組，可以將這些相依項新增至 `.zip` 檔案。為此，可以執行 `npm install` 命令，在 `node_modules` 目錄中安裝函式所需的程式庫。下列 CLI 命令範例會建立名為 `my_deployment_package.zip` 的 `.zip` 檔案，其中包含 `index.js` 或 `index.mjs` 檔案 (Synthetics 處理常式) 及其相依項。在此範例中，可以使用 `npm` 套件管理工具來安裝相依項。

```
~/my_function
├── index.mjs
├── synthetics.json
├── myhelper-util.mjs    
└── node_modules
    ├── mydependency
```

在根目錄建立包含專案資料夾內容的 `.zip` 檔案。使用 `r` (遞迴) 選項，如下列範例所示，以確保 `zip` 壓縮子資料夾。

```
zip -r my_deployment_package.zip .
```

新增 Synthetics 設定檔來設定 CloudWatch Synthetics 的行為。您可以建立 `synthetics.json` 檔案，並將其儲存在與進入點或處理常式檔案相同的路徑。

或者，也可以將進入點檔案儲存在您選擇的資料夾結構中。不過，請確定已在處理常式名稱中指定資料夾路徑。

 **處理常式名稱** 

請務必將 Canary 的指令碼進入點 (處理常式) 設定為 ` myCanaryFilename.functionName`，以符合指令碼進入點的檔案名稱。可以選擇將 Canary 儲存在單獨的資料夾 (例如 ` myFolder/my_canary_filename.mjs`) 中。如果將其存放在單獨的資料夾中，請在指令碼進入點中指定該路徑，例如 ` myFolder/my_canary_filename.functionName`。

## 變更現有 Playwright 指令碼以用作 CloudWatch Synthetics Canary
<a name="CloudWatch_Synthetics_canary_edit_Playwright_script"></a>

可以編輯 Node.js 和 Playwright 的現有指令碼，以用作 Canary。如需 Playwright 的詳細資訊，請參閱 [Playwright 程式庫](https://playwright.dev/docs/api/class-playwright)文件。

可以使用儲存在檔案 ` exampleCanary.mjs` 中的下列 Playwright 指令碼。

```
import { chromium } from 'playwright';
import { expect } from '@playwright/test';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com', {timeout: 30000});
await page.screenshot({path: 'example-home.png'});

const title = await page.title();
expect(title).toEqual("Example Domain");
 
await browser.close();
```

執行下列步驟來轉換指令碼：

1. 建立和匯出 `handler` 函數。處理常式是指令碼的進入點函數。您可以為處理常式函式選擇任何名稱，但指令碼中使用的函式應該與 Canary 處理常式中的函式相同。如果您的指令碼名稱為 `exampleCanary.mjs`，且處理常式函式名稱為 `myhandler`，則您的 Canary 處理常式會命名為 `exampleCanary.myhandler`。在下列範例中，處理常式函式名稱為 `handler`。

   ```
   exports.handler = async () => {
     // Your script here
     };
   ```

1. 將 `Synthetics Playwright module` 作為相依項匯入。

   ```
   import { synthetics } from '@aws/synthetics-playwright';
   ```

1. 使用 Synthetics `Launch` 函式啟動瀏覽器。

   ```
   const browser = await synthetics.launch();
   ```

1. 使用 Synthetics `newPage` 函式建立新的 Playwright 頁面。

   ```
   const page = await synthetics.newPage();
   ```

指令碼現在已準備好作為 Synthetics Canary 執行。以下是更新的指令碼：

 **已更新 ES6 格式的指令碼** 

以 `.mjs` 副檔名儲存的指令碼檔案。

```
import { synthetics } from '@aws/synthetics-playwright';
import { expect } from '@playwright/test';

export const handler = async (event, context) => {
  try {
        // Launch a browser
        const browser = await synthetics.launch();
        
        // Create a new page
        const page = await synthetics.newPage(browser);
        
        // Navigate to a website
        await page.goto('https://www.example.com', {timeout: 30000});
        
        // Take screenshot
        await page.screenshot({ path: '/tmp/example.png' });
        
        // Verify the page title
        const title = await page.title();
        expect(title).toEqual("Example Domain");
    } finally {
        // Ensure browser is closed
        await synthetics.close();
    }
};
```

 **已更新 CommonJS 格式的指令碼** 

以 `.js` 副檔名儲存的指令碼檔案。

```
const { synthetics } = require('@aws/synthetics-playwright');
const { expect } = require('@playwright/test');

exports.handler = async (event) => {
  try {
    const browser = await synthetics.launch();
    const page = await synthetics.newPage(browser);
    await page.goto('https://www.example.com', {timeout: 30000});
    await page.screenshot({ path: '/tmp/example.png' });
    const title = await page.title();
    expect(title).toEqual("Example Domain");
  } finally {
    await synthetics.close();
  }
};
```

## CloudWatch Synthetics 組態
<a name="Synthetics_canary_configure_Playwright_script"></a>

您可以提供名為 `synthetics.json` 的選用 JSON 設定檔，設定 Synthetics Playwright 執行時期的行為。此檔案應封裝在與處理常式檔案相同的位置。雖然設定檔是選用的，但如果您未提供設定檔，或者設定金鑰缺失，CloudWatch 會使用預設值。

 **封裝您的設定檔** 

以下是支援的組態值及其預設值。

```
{
    "step": {
        "screenshotOnStepStart": false,
        "screenshotOnStepSuccess": false,
        "screenshotOnStepFailure": false,
        "stepSuccessMetric": true,
        "stepDurationMetric": true,
        "continueOnStepFailure": true,
        "stepsReport": true
    },
    "report": {
        "includeRequestHeaders": true,
        "includeResponseHeaders": true,
        "includeUrlPassword": false,
        "includeRequestBody": true,
        "includeResponseBody": true,
        "restrictedHeaders": ['x-amz-security-token', 'Authorization'], // Value of these headers is redacted from logs and reports
        "restrictedUrlParameters": ['Session', 'SigninToken'] // Values of these url parameters are redacted from logs and reports
    },
    "logging": {
        "logRequest": false,
        "logResponse": false,
        "logResponseBody": false,
        "logRequestBody": false,
        "logRequestHeaders": false,
        "logResponseHeaders": false
    },
    "httpMetrics": {
        "metric_2xx": true,
        "metric_4xx": true,
        "metric_5xx": true,
        "failedRequestsMetric": true,
        "aggregatedFailedRequestsMetric": true,
        "aggregated2xxMetric": true,
        "aggregated4xxMetric": true,
        "aggregated5xxMetric": true
    },
    "canaryMetrics": {
        "failedCanaryMetric": true,
        "aggregatedFailedCanaryMetric": true
    },
    "userAgent": "",
    "har": true
}
```

 **步驟組態** 
+ `screenshotOnStepStart` – 確定 Synthetics 是否應在步驟開始前擷取螢幕畫面。預設值為 `true`。
+ `screenshotOnStepSuccess` – 確定 Synthetics 是否應在步驟成功後擷取螢幕畫面。預設值為 `true`。
+ `screenshotOnStepFailure` – 確定 Synthetics 是否應在步驟失敗後擷取螢幕畫面。預設值為 `true`。
+ `continueOnStepFailure` – 確定指令碼是否應在步驟失敗後繼續。預設值為 `false`。
+ `stepSuccessMetric` – 確定步驟的 ` SuccessPercent` 指標是否已發出。對於 Canary 執行，如果步驟成功，該步驟的 `SuccessPercent` 指標為 `100`；如果步驟失敗，則指標為 `0`。預設值為 `true`。
+ `stepDurationMetric` – 確定步驟的 `Duration` 指標是否已發出。`Duration` 指標以步驟執行的持續時間發出，以毫秒為單位。預設值為 `true`。

 **報告組態** 

包括 CloudWatch Synthetics 產生的所有報告，例如 HAR 檔案和 Synthetics 步驟報告。敏感資料修訂欄位 `restrictedHeaders` 和 `restrictedUrlParameters` 也適用於 Synthetics 產生的日誌。
+ `includeRequestHeaders` – 是否要在報告中包含請求標頭。預設值為 `false`。
+ `includeResponseHeaders` – 是否要在報告中包含回應標頭。預設值為 `false`。
+ `includeUrlPassword` – 是否要包含在 URL 中顯示的密碼。依預設，URL 中顯示的密碼會從日誌和報告進行修訂，以防止揭露敏感資料。預設值為 `false`。
+ `includeRequestBody` – 是否要在報告中包含請求內文。預設值為 `false`。
+ `includeResponseBody` – 是否要在報告中包含回應內文。預設值為 `false`。
+ `restrictedHeaders` – 如果包含標頭，則要忽略的標頭值清單。這適用於請求和回應標頭。例如，可以透過將 `includeRequestHeaders` 傳遞為 true，將 `restrictedHeaders` 傳遞為 `['Authorization']` 來隱藏憑證。
+ `restrictedUrlParameters` – 要修訂的 URL 路徑或查詢參數清單。這適用於出現在日誌、報告和錯誤中的 URL。參數區分大小寫。您可以將星號 (`*`) 傳遞為數值，以修訂所有 URL 路徑和查詢參數值。預設為空陣列。
+ `har` – 確定是否應產生 HTTP 封存 (HAR)。預設值為 `true`。

以下是報告設定檔範例。

```
"includeRequestHeaders": true,
"includeResponseHeaders": true,
"includeUrlPassword": false,
"includeRequestBody": true,
"includeResponseBody": true,
"restrictedHeaders": ['x-amz-security-token', 'Authorization'], // Value of these headers is redacted from logs and reports
"restrictedUrlParameters": ['Session', 'SigninToken'] // Values of these URL parameters are redacted from logs and reports
```

 **記錄組態** 

適用於 CloudWatch Synthetics 產生的日誌。控制請求和回應日誌的詳盡程度。
+ `logRequest` – 是否要在 Canary 日誌中記錄每個請求。對於 UI Canary，這會記錄瀏覽器傳送的每個請求。預設值為 ` false`。
+ `logResponse` – 是否要在 Canary 日誌中記錄每個回應。對於 UI Canary，這會記錄瀏覽器收到的每個回應。預設值為 ` false`。
+ `logRequestBody` – 是否要在 Canary 日誌中記錄請求內文及請求。此組態僅在 `logRequest` 為 true 時適用。預設值為 `false`。
+ `logResponseBody` – 是否要在 Canary 日誌中記錄回應內文及請求。此組態僅在 `logResponse` 為 true 時適用。預設值為 `false`。
+ `logRequestHeaders` – 是否要在 Canary 日誌中記錄請求標頭及請求。此組態僅在 ` logRequest` 為 true 時適用。預設值為 `false`。
+ `logResponseHeaders` – 是否要在 Canary 日誌中記錄回應標頭及回應。此組態僅在 ` logResponse` 為 true 時適用。預設值為 `false`。

 **HTTP 指標組態** 

與具有不同 HTTP 狀態碼之網路請求計數相關的指標組態，由 CloudWatch Synthetics 針對此 Canary 發出。
+ `metric_2xx` – 是否為此 Canary 發出 `2xx` 指標 (包含 `CanaryName` 維度)。預設值為 ` true`。
+ `metric_4xx` – 是否為此 Canary 發出 `4xx` 指標 (包含 `CanaryName` 維度)。預設值為 ` true`。
+ `metric_5xx` – 是否為此 Canary 發出 `5xx` 指標 (包含 `CanaryName` 維度)。預設值為 ` true`。
+ `failedRequestsMetric` – 是否為此 Canary 發出 ` failedRequests` 指標 (包含 `CanaryName` 維度)。預設值為 `true`。
+ `aggregatedFailedRequestsMetric` – 是否為此 Canary 發出 ` failedRequests` 指標 (不含 `CanaryName` 維度)。預設值為 `true`。
+ `aggregated2xxMetric` – 是否為此 Canary 發出 `2xx` 指標 (不含 `CanaryName` 維度)。預設值為 `true`。
+ `aggregated4xxMetric` – 是否為此 Canary 發出 `4xx` 指標 (不含 `CanaryName` 維度)。預設值為 `true`。
+ `aggregated5xxMetric` – 是否為此 Canary 發出 `5xx` 指標 (不含 `CanaryName` 維度)。預設值為 `true`。

 **Canary 指標組態** 

CloudWatch Synthetics 發出之其他指標的組態。
+ `failedCanaryMetric` – 是否為此 Canary 發出 `Failed` 指標 (包含 `CanaryName` 維度)。預設值為 ` true`。
+ `aggregatedFailedCanaryMetric` – 是否為此 Canary 發出 ` Failed` 指標 (不含 `CanaryName` 維度)。預設值為 `true`。

 **其他組態** 
+ `userAgent` – 要附加至使用者代理程式的字串。使用者代理程式是包含在請求標頭中的字串，用於在您使用無周邊瀏覽器造訪網站時，識別您的瀏覽器。CloudWatch Synthetics 會自動新增 `CloudWatchSynthetics/{{canary-arn}} to the user agent`。指定的組態會附加到產生的使用者代理程式。預設使用者代理程式值為空白字串 (`""`)。

### CloudWatch Synthetics 環境變數
<a name="Synthetics_canary_Nodejs_Playwright_script"></a>

使用環境變數設定記錄層級和格式。

 **日誌格式** 

CloudWatch Synthetics Playwright 執行時期會為每個 Canary 執行建立 CloudWatch 日誌。日誌以 JSON 格式撰寫，方便查詢。或者，您可以將日誌格式變更為 `TEXT`。
+ `Environment variable name` – CW\_SYNTHETICS\_LOG\_FORMAT 
+ `Supported values` – JSON、TEXT 
+ `Default` – JSON 

 **日誌層級** 

雖然啟用 `Debug` 模式會提升詳盡程度，但對於疑難排解很有用。
+ `Environment variable name` – CW\_SYNTHETICS\_LOG\_LEVEL
+ `Supported values` – TRACE、DEBUG、INFO、WARN、ERROR、FATAL 
+ `Default` – INFO