Один из сценариев, над которым мне приходилось работать в последние дни, заключается в создании персонализированных тестов доступности, чтобы убедиться, что веб-сайт по-прежнему активен, даже когда вокруг нет посетителей. Для выполнения этой задачи я использовал 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 вы увидите что-то вроде этого:

Как видите, зеленые точки означают, что все в порядке, а крестики, которые я вызвал, просто остановив веб-приложение 😉, означают, что этот тест не пройден. Суть в том, что вы можете настроить оповещения, чтобы уведомлять вас, когда что-то перестает работать. Для этого у вас есть следующие сигналы при настройке оповещения: