GitHub user dosubot[bot] added a comment to the discussion: How can I integrate 
Superset charts with PlayWright to ensure that all charts and data on the page 
are fully rendered and there are no unexpected errors before taking a 
screenshot?

<!-- Answer -->
To ensure all Superset charts and data are fully rendered and error-free before 
taking a screenshot with Playwright in C#, follow the same logic used by 
Superset's built-in Playwright automation:

1. Navigate to your Superset dashboard or chart URL.
2. Wait for the main container (e.g., `.dashboard` or the relevant class) to 
appear.
3. Wait for all `.chart-container` elements to be visible.
4. Wait for all `.loading` elements to disappear (state "detached"), which 
means charts have finished rendering.
5. (Optional) Wait a few seconds for chart animations to complete.
6. Check for error elements with `role="alert"` and extract error messages from 
`.antd5-modal-content .antd5-modal-body` if present.
7. Take the screenshot.

Here’s a C# Playwright code snippet that implements this logic:

```csharp
using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new 
BrowserTypeLaunchOptions { Headless = true });
var page = await browser.NewPageAsync();

await page.GotoAsync("https://your-superset-url/superset/dashboard/123/";, new 
PageGotoOptions { WaitUntil = WaitUntilState.Load });

// Wait for main dashboard container
await page.WaitForSelectorAsync(".dashboard");

// Wait for all chart containers to be visible
var chartContainers = await page.QuerySelectorAllAsync(".chart-container");
foreach (var chart in chartContainers)
{
    await chart.WaitForElementStateAsync(ElementState.Visible);
}

// Wait for all loading spinners to disappear
var loadingElements = await page.QuerySelectorAllAsync(".loading");
foreach (var loading in loadingElements)
{
    await loading.WaitForElementStateAsync(ElementState.Detached);
}

// Optional: wait for chart animations to finish
await page.WaitForTimeoutAsync(5000);

// Check for unexpected errors
var alerts = await page.QuerySelectorAllAsync("[role='alert']");
foreach (var alert in alerts)
{
    var seeMoreBtn = await alert.QuerySelectorAsync("[role='button']");
    if (seeMoreBtn != null)
    {
        await seeMoreBtn.ClickAsync();
        var modalBody = await page.QuerySelectorAsync(".antd5-modal-content 
.antd5-modal-body");
        if (modalBody != null)
        {
            var errorMsg = await modalBody.InnerTextAsync();
            // Handle or log errorMsg as needed
        }
        var closeBtn = await page.QuerySelectorAsync(".antd5-modal-content 
.antd5-modal-close");
        if (closeBtn != null)
            await closeBtn.ClickAsync();
        await page.WaitForSelectorAsync(".antd5-modal-content", new 
PageWaitForSelectorOptions { State = WaitForSelectorState.Detached });
    }
}

// Take the screenshot
await page.ScreenshotAsync(new PageScreenshotOptions { Path = "dashboard.png" 
});
```

For large dashboards, consider a tiled screenshot approach: scroll the 
dashboard in view-sized increments, wait for content to settle after each 
scroll, and stitch the images together. This is how Superset handles dashboards 
that extend beyond the viewport 
[[source]](https://github.com/apache/superset/pull/34561).

You can tune timeouts and delays using Superset config options like 
`SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT`, `SCREENSHOT_SELENIUM_ANIMATION_WAIT`, 
and `SCREENSHOT_SELENIUM_HEADSTART` 
[[source]](https://github.com/apache/superset/blob/master/superset/config.py).

There are no C#-specific examples in the Superset codebase, but the DOM 
structure and selectors are the same as in Python, so this approach is portable 
[[source]](https://github.com/apache/superset/discussions/36839).


<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*

---
<sup>How did I do? 
[Good](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=great_response)
 | 
[Irrelevant](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=irrelevant_answer)
 | 
[Incorrect](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=incorrect_sources)
 | 
[Verbose](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=too_verbose)
 | 
[Hallucination](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=hallucination)
 | [Report 
🐛](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=bug_report)
 | 
[Other](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=other)</sup>

[![Chat with 
Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github)&nbsp;[![Open
 in 
Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=To%20ensure%20all%20Superset%20charts%20and%20data%20are%20fully%20rendered%20and%20error-free%20before%20taking%20a%20screenshot%20with%20Playwright%20in%20C%23%2C%20follow%20the%20same%20logic%20used%20by%20Superset%27s%20built-in%20Playwright%20automation%3A%0A%0A1.%20Navigate%20to%20your%20Superset%20dashboard%20or%20chart%20URL.%0A2.%20Wait%20for%20the%20main%20container%20%28e.g.%2C%20%60.dashboard%60%20or%20the%20relevant%20class%29%20to%20appear.%0A3.%20Wait%20for%20all%20%60.chart-container%60%20elements%20to%20be%20visible.%0A4.%20Wait%20for%20all%20%60.loading%60%20elements%20to%20disappear%20%28state%20%22detached%22%29%2C%20which%20means%20charts%20have%20finished%20rendering.%0A5.%20%28Optional%29%20Wait%20a%20few%20seconds%20for%20chart
 
%20animations%20to%20complete.%0A6.%20Check%20for%20error%20elements%20with%20%60role%3D%22alert%22%60%20and%20extract%20error%20messages%20from%20%60.antd5-modal-content%20.antd5-modal-body%60%20if%20present.%0A7.%20Take%20the%20screenshot.%0A%0AHere%E2%80%99s%20a%20C%23%20Playwright%20code%20snippet%20that%20implements%20this%20logic%3A%0A%0A%60%60%60csharp%0Ausing%20Microsoft.Playwright%3B%0A%0Ausing%20var%20playwright%20%3D%20await%20Playwright.CreateAsync%28%29%3B%0Aawait%20using%20var%20browser%20%3D%20await%20playwright.Chromium.LaunchAsync%28new%20BrowserTypeLaunchOptions%20%7B%20Headless%20%3D%20true%20%7D%29%3B%0Avar%20page%20%3D%20await%20browser.NewPageAsync%28%29%3B%0A%0Aawait%20page.GotoAsync%28%22https%3A//your-superset-url/superset/dashboard/123/%22%2C%20new%20PageGotoOptions%20%7B%20WaitUntil%20%3D%20WaitUntilState.Load%20%7D%29%3B%0A%0A//%20Wait%20for%20main%20dashboard%20container%0Aawait%20page.WaitForSelectorAsync%28%22.dashboard%22%29%3B%0A%0A//%20Wait%20for%20
 
all%20chart%20containers%20to%20be%20visible%0Avar%20chartContainers%20%3D%20await%20page.QuerySelectorAllAsync%28%22.chart-container%22%29%3B%0Aforeach%20%28var%20chart%20in%20chartContainers%29%0A%7B%0A%20%20%20%20await%20chart.WaitForElementStateAsync%28ElementState.Visible%29%3B%0A%7D%0A%0A//%20Wait%20for%20all%20loading%20spinners%20to%20disappear%0Avar%20loadingElements%20%3D%20await%20page.QuerySelectorAllAsync%28%22.loading%22%29%3B%0Aforeach%20%28var%20loading%20in%20loadingElements%29%0A%7B%0A%20%20%20%20await%20loading.WaitForElementStateAsync%28ElementState.Detached%29%3B%0A%7D%0A%0A//%20Optional%3A%20wait%20for%20chart%20animations%20to%20finish%0Aawait%20page.WaitForTimeoutAsync%285000%29%3B%0A%0A//%20Check%20for%20unexpected%20errors%0Avar%20alerts%20%3D%20await%20page.QuerySelectorAllAsync%28%22%5Brole%3D%27alert%27%5D%22%29%3B%0Aforeach%20%28var%20alert%20in%20alerts%29%0A%7B%0A%20%20%20%20var%20seeMoreBtn%20%3D%20await%20alert.QuerySelectorAsync%28%22%5Brole%3D%27b
 
utton%27%5D%22%29%3B%0A%20%20%20%20if%20%28seeMoreBtn%20%21%3D%20null%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20await%20seeMoreBtn.ClickAsync%28%29%3B%0A%20%20%20%20%20%20%20%20var%20modalBody%20%3D%20await%20page.QuerySelectorAsync%28%22.antd5-modal-content%20.antd5-modal-body%22%29%3B%0A%20%20%20%20%20%20%20%20if%20%28modalBody%20%21%3D%20null%29%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20errorMsg%20%3D%20await%20modalBody.InnerTextAsync%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Handle%20or%20log%20errorMsg%20as%20needed%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20var%20closeBtn%20%3D%20await%20page.QuerySelectorAsync%28%22.antd5-modal-content%20.antd5-modal-close%22%29%3B%0A%20%20%20%20%20%20%20%20if%20%28closeBtn%20%21%3D%20null%29%0A%20%20%20%20%20%20%20%20%20%20%20%20await%20closeBtn.ClickAsync%28%29%3B%0A%20%20%20%20%20%20%20%20await%20page.WaitForSelectorAsync%28%22.antd5-modal-content%22%2C%20new%20PageWaitForSelecto
 
rOptions%20%7B%20State%20%3D%20WaitForSelectorState.Detached%20%7D%29%3B%0A%20%20%20%20%7D%0A%7D%0A%0A//%20Take%20the%20screenshot%0Aawait%20page.ScreenshotAsync%28new%20PageScreenshotOptions%20%7B%20Path%20%3D%20%22dashboard.png%22%20%7D%29%3B%0A%60%60%60%0A%0AFor%20large%20dashboards%2C%20consider%20a%20tiled%20screenshot%20approach%3A%20scroll%20the%20dashboard%20in%20view-sized%20increments%2C%20wait%20for%20content%20to%20settle%20after%20each%20scroll%2C%20and%20stitch%20the%20images%20together.%20This%20is%20how%20Superset%20handles%20dashboards%20that%20extend%20beyond%20the%20viewport%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/pull/34561%29.%0A%0AYou%20can%20tune%20timeouts%20and%20delays%20using%20Superset%20config%20options%20like%20%60SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT%60%2C%20%60SCREENSHOT_SELENIUM_ANIMATION_WAIT%60%2C%20and%20%60SCREENSHOT_SELENIUM_HEADSTART%60%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/blob/master/superset/config.p
 
y%29.%0A%0AThere%20are%20no%20C%23-specific%20examples%20in%20the%20Superset%20codebase%2C%20but%20the%20DOM%20structure%20and%20selectors%20are%20the%20same%20as%20in%20Python%2C%20so%20this%20approach%20is%20portable%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/discussions/36839%29.)&nbsp;[![Join
 
Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share
 on 
X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)

GitHub link: 
https://github.com/apache/superset/discussions/36845#discussioncomment-15349414

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: 
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to