BCards/src/BCards.IntegrationTests/Helpers/PuppeteerTestHelper.cs
2025-07-14 23:21:25 -03:00

195 lines
5.4 KiB
C#

using PuppeteerSharp;
using Microsoft.AspNetCore.Mvc.Testing;
namespace BCards.IntegrationTests.Helpers;
public class PuppeteerTestHelper : IAsyncDisposable
{
private IBrowser? _browser;
private IPage? _page;
private readonly string _baseUrl;
public PuppeteerTestHelper(WebApplicationFactory<Program> factory)
{
_baseUrl = factory.Server.BaseAddress?.ToString() ?? "https://localhost:49178";
}
public async Task InitializeAsync()
{
// Download Chrome if not available
await new BrowserFetcher().DownloadAsync();
_browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true, // Set to false for debugging
Args = new[]
{
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--disable-web-security",
"--allow-running-insecure-content",
"--ignore-certificate-errors"
}
});
_page = await _browser.NewPageAsync();
// Set viewport for consistent testing
await _page.SetViewportAsync(new ViewPortOptions
{
Width = 1920,
Height = 1080
});
}
public IPage Page => _page ?? throw new InvalidOperationException("PuppeteerTestHelper not initialized. Call InitializeAsync first.");
public async Task NavigateToAsync(string relativeUrl)
{
var fullUrl = new Uri(new Uri(_baseUrl), relativeUrl).ToString();
await Page.GoToAsync(fullUrl, new NavigationOptions
{
WaitUntil = new[] { WaitUntilNavigation.Networkidle0 }
});
}
public async Task<string> GetPageContentAsync()
{
return await Page.GetContentAsync();
}
public async Task<string> GetPageTitleAsync()
{
return await Page.GetTitleAsync();
}
public async Task<bool> ElementExistsAsync(string selector)
{
try
{
await Page.WaitForSelectorAsync(selector, new WaitForSelectorOptions
{
Timeout = 5000
});
return true;
}
catch (WaitTaskTimeoutException)
{
return false;
}
}
public async Task ClickAsync(string selector)
{
await Page.WaitForSelectorAsync(selector);
await Page.ClickAsync(selector);
}
public async Task TypeAsync(string selector, string text)
{
await Page.WaitForSelectorAsync(selector);
await Page.TypeAsync(selector, text);
}
public async Task FillFormAsync(Dictionary<string, string> formData)
{
foreach (var kvp in formData)
{
await Page.WaitForSelectorAsync(kvp.Key);
await Page.EvaluateExpressionAsync($"document.querySelector('{kvp.Key}').value = ''");
await Page.TypeAsync(kvp.Key, kvp.Value);
}
}
public async Task SubmitFormAsync(string formSelector)
{
await Page.ClickAsync($"{formSelector} button[type='submit'], {formSelector} input[type='submit']");
}
public async Task WaitForNavigationAsync()
{
await Page.WaitForNavigationAsync(new NavigationOptions
{
WaitUntil = new[] { WaitUntilNavigation.Networkidle0 }
});
}
public async Task WaitForElementAsync(string selector, int timeoutMs = 10000)
{
await Page.WaitForSelectorAsync(selector, new WaitForSelectorOptions
{
Timeout = timeoutMs
});
}
public async Task<string> GetElementTextAsync(string selector)
{
await Page.WaitForSelectorAsync(selector);
var element = await Page.QuerySelectorAsync(selector);
var text = await Page.EvaluateFunctionAsync<string>("el => el.textContent", element);
return text?.Trim() ?? string.Empty;
}
public async Task<string> GetElementValueAsync(string selector)
{
await Page.WaitForSelectorAsync(selector);
var element = await Page.QuerySelectorAsync(selector);
var value = await Page.EvaluateFunctionAsync<string>("el => el.value", element);
return value ?? string.Empty;
}
public async Task<bool> IsElementVisibleAsync(string selector)
{
try
{
await Page.WaitForSelectorAsync(selector, new WaitForSelectorOptions
{
Visible = true,
Timeout = 2000
});
return true;
}
catch (WaitTaskTimeoutException)
{
return false;
}
}
public async Task TakeScreenshotAsync(string fileName)
{
await Page.ScreenshotAsync(fileName);
}
public async Task<string> GetCurrentUrlAsync()
{
return Page.Url;
}
public async Task<List<string>> GetAllElementTextsAsync(string selector)
{
var elements = await Page.QuerySelectorAllAsync(selector);
var texts = new List<string>();
foreach (var element in elements)
{
var text = await Page.EvaluateFunctionAsync<string>("el => el.textContent", element);
texts.Add(text?.Trim() ?? string.Empty);
}
return texts;
}
public async ValueTask DisposeAsync()
{
if (_page != null)
{
await _page.CloseAsync();
}
if (_browser != null)
{
await _browser.CloseAsync();
}
}
}