Один из сценариев, над которым мне приходилось работать в последние дни, заключается в создании персонализированных тестов доступности, чтобы убедиться, что веб-сайт по-прежнему активен, даже когда вокруг нет посетителей. Для выполнения этой задачи я использовал Node.js в качестве языка программирования и библиотеку драматурга для имитации необходимой навигации, чтобы убедиться, что все работает правильно:
Что такое Драматург?
Playwright — это API, с помощью которого вы можете автоматизировать Chromium, Firefox и WebKit и таким образом тестировать свои приложения с функциональной точки зрения.
Он имеет SDK для Node.js, Java, Python и .NET. В этой статье мы будем использовать последний.
Вход в Azure Active Directory с Playwright
Первое, что нужно сделать, это создать консольное приложение:
dotnet new console -n web-with-az-ad-playwright-dotnet
Далее вам нужно добавить библиотеку Playwright:
dotnet add package Microsoft.Playwright
И это код, который я использовал:
//// See https://aka.ms/new-console-template for more information
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync(); await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false });
//3. Authenticate with Azure AD Console.WriteLine("Testing authenticated web page with Azure AD");
var page = await browser.NewPageAsync(); await page.GotoAsync("<WEB_URL>");
//Interact with the login form:
//email await page.FillAsync("input[type='email']", "<VALID_USER_EMAIL>"); await page.ClickAsync("input[type='submit']");
await page.WaitForNavigationAsync();
//password await page.ClickAsync("[placeholder='Password']"); await page.FillAsync("input[name='passwd']", "<VALID_USER_PASSWORD>"); await page.ClickAsync("input[type='submit']");
//Stay signed? Say no await page.ClickAsync("text=No");
await page.WaitForNavigationAsync();
// await page.PauseAsync(); //Just for debugging
var title = await page.TitleAsync();
Console.WriteLine($"Title of the page {title}");
Примечание: если вас удивил исходный код или вы считаете, что в нем чего-то не хватает 😀, взгляните на эту ссылку: https://aka.ms/new-console-template
Если вы запустите его с помощью Headless, вы увидите, как создается экземпляр Chromium и быстро выполняет все эти шаги. Если вы делаете что-то подобное и не знаете ни одного из своих веб-селекторов, вы можете использовать page.PauseAsync(), который остановит процесс и позволит вам изучить веб-поля и вернуть селектор к вам.
После этого, если вы войдете в это веб-приложение, вы увидите эту страницу по умолчанию:
Тест с Node.js и Playwright
Следующее, что вам нужно сделать, это тест. Это может быть даже расположено в консольном приложении, и для этого вы можете использовать функции Azure с триггером типа таймера:
const { chromium } = require('playwright-chromium'); const appInsights = require("applicationinsights"); const { v4 } = require('uuid'); var telemetryClient = new appInsights.TelemetryClient(process.env.APP_INSIGHTS_WEB); const Stopwatch = require('statman-stopwatch');
module.exports = async function(context, myTimer) { var timeStamp = new Date().toISOString();
if (myTimer.isPastDue) { context.log('JavaScript is running late!'); } context.log('JavaScript timer trigger function ran!', timeStamp);
//Create availability telemetry var availabilityTelemetry = { id: v4(), name: process.env.AVAILABILITY_TEST_NAME, runLocation: process.env.RUN_LOCATION, success: false };
const stopwatch = new Stopwatch(); const browser = await chromium.launch({ headless: true });
try { //Create playwright flow const page = await browser.newPage(); stopwatch.start();
context.log(`Navigating to: ${process.env.WEB_URL}`); await page.goto(process.env.WEB_URL); context.log(`Put the email ${process.env.TEST_USER_EMAIL}`); await page.type("input[type='email']", process.env.TEST_USER_EMAIL); await page.click("input[type='submit']"); await page.waitForNavigation();
context.log('Put the password'); await page.click("[placeholder='Password']"); await page.type("input[name='passwd']", process.env.TEST_USER_PWD); await page.click("input[type='submit']"); await page.waitForNavigation();
context.log('Say no'); await page.click("text=No"); await page.waitForNavigation();
var title = await page.title(); context.log('Title: ' + title); availabilityTelemetry.success = true;
} catch (error) { context.log.error('Error: ' + error); availabilityTelemetry.success = false;
//Create exception telemetry telemetryClient.trackException({ exception: error });
} finally { stopwatch.stop(); var elapsed = stopwatch.read(); context.log('Stopwatch: ' + elapsed); availabilityTelemetry.duration = elapsed; telemetryClient.trackAvailability(availabilityTelemetry); await browser.close(); context.done(); } }
Каждую 1 минуту мы запускаем этот тест с Playwright. Мы пытаемся войти в систему с именем пользователя и паролем, которые мы получили из переменных среды (в идеале они должны храниться в Azure Key Vault), и, наконец, мы получаем заголовок страницы, который должен быть таким же, как пример страницы.
Если вы можете пройти все шаги без тайм-аута (например, из-за того, что он не может найти элемент управления), это означает, что все было выполнено без каких-либо проблем, и, следовательно, тест в порядке. В противном случае будет создано исключение в самой Application Insights.
Для развертывания этого примера я использовал код Visual Studio, но я создал и настроил функции Azure с помощью Azure CLI, чтобы также добавить соответствующие параметры приложения:
#Variables #for the Azure Function TEST_USER="<AZURE_AD_USER_EMAIL>" TEST_SECRET="<AZURE_AD_USER_PASSWORD>" WEB_TO_TEST="<THE_WEB_YOU_WANT_TO_TEST>" APP_INSIGHTS_TO_REPORT="<APP_INSIGHTS_INSTRUMENTATION_KEY>" AVAILABILITY_TEST_NAME="Test using Node.js"
#for Azure resources RESOURCE_GROUP="Custom-Tests" LOCATION="West Europe" AZURE_FUNCTION_NAME="app-insights-availability-west" AZURE_FUNCTION_PLAN="AzFuncNodejsPlan" STORAGE_ACCOUNT_NAME="playwrightnodejswest"
#1. Create Resource Group az group create --name $RESOURCE_GROUP --location $LOCATION
#2. Create Storage account az storage account create --resource-group $RESOURCE_GROUP --name $STORAGE_ACCOUNT_NAME --location $LOCATION --sku Standard_LRS
#Get Azure Storage connection string STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name $STORAGE_ACCOUNT_NAME --resource-group $RESOURCE_GROUP --output tsv)
#Create Azure Function Plan az functionapp plan create --resource-group $RESOURCE_GROUP --name $AZURE_FUNCTION_PLAN --location $LOCATION --number-of-workers 1 --sku EP1 --is-linux
# Create Azure Function az functionapp create --name $AZURE_FUNCTION_NAME --functions-version 3 --storage-account $STORAGE_ACCOUNT_NAME --resource-group $RESOURCE_GROUP --plan $AZURE_FUNCTION_PLAN --runtime node --runtime-version 12
#Add app settings to the Azure Function az functionapp config appsettings set --name $AZURE_FUNCTION_NAME --resource-group $RESOURCE_GROUP \ --settings WEB_URL=$WEB_TO_TEST \ RUN_LOCATION=$LOCATION \ TEST_USER_EMAIL=$TEST_USER \ TEST_USER_PWD=$TEST_SECRET \ APP_INSIGHTS_WEB=$APP_INSIGHTS_TO_REPORT \ AVAILABILITY_TEST_NAME=$AVAILABILITY_TEST_NAME \ PLAYWRIGHT_BROWSERS_PATH=0
Примечание. В этом примере я развертываю его в Visual Studio Code. Если вы создали собственную функцию Azure, имейте в виду, что для работы Playwright в этой службе необходимо указать, что вы хотите, чтобы установка зависимостей выполнялась в месте назначения. Это достигается изменением файла .vscode/settings.json.
{
"azureFunctions.deploySubpath": ".",
"azureFunctions.projectLanguage": "JavaScript",
"azureFunctions.projectRuntime": "~3",
"debug.internalConsoleOptions": "neverOpen",
"azureFunctions.scmDoBuildDuringDeployment": true
}
Результат
Если вы запустите этот тест на некоторое время, в разделе Доступность Application Insights вы увидите что-то вроде этого:
Как видите, зеленые точки означают, что все в порядке, а крестики, которые я вызвал, просто остановив веб-приложение 😉, означают, что этот тест не пройден. Суть в том, что вы можете настроить оповещения, чтобы уведомлять вас, когда что-то перестает работать. Для этого у вас есть следующие сигналы при настройке оповещения: