Developer-Dashboard

 view release on metacpan or  search on metacpan

t/27-sql-dashboard-playwright.t  view on Meta::CPAN

    );
    _wait_for_http("http://127.0.0.1:$dashboard_port/app/sql-dashboard");

    my ( $script_fh, $script_path ) = tempfile( 'sql-dashboard-playwright-XXXXXX', SUFFIX => '.js', TMPDIR => 1 );
    print {$script_fh} _playwright_script();
    close $script_fh or die "Unable to close Playwright script $script_path: $!";

    my $playwright_result = _run_command(
        command => [ $node_bin, $script_path ],
        env     => {
            PLAYWRIGHT_DIR => $playwright_dir,
            CHROMIUM_BIN   => $chromium_bin,
            DASHBOARD_URL  => "http://127.0.0.1:$dashboard_port/app/sql-dashboard",
        },
        label => 'Playwright sql-dashboard flow',
    );

    is( $playwright_result->{stderr}, '', 'sql-dashboard Playwright flow does not emit stderr' );
    my $payload = _json_decode( $playwright_result->{stdout} );
    ok( $payload->{ok}, 'sql-dashboard Playwright flow reports success' );
    ok( $payload->{profile_saved}, 'sql-dashboard Playwright flow confirmed that the profile save completed before share-url deletion checks' );
    is( $payload->{saved_driver}, 'DBD::Mock', 'sql-dashboard Playwright flow saved the expected driver module' );

    my $saved_profile = File::Spec->catfile( $config_root, 'Playwright Profile.json' );
    my $saved_collection = File::Spec->catfile( $collection_root, 'Shared Queries.json' );
    ok( !-e $saved_profile, 'browser-created sql profile is removed after the shared-url draft restoration check deletes it' );
    ok( -f $saved_collection, 'browser-created sql collection persists to config/sql-dashboard/collections' );
    is( _mode_octal($config_root), '0700', 'browser-created sql profile root is owner-only' );
    is( _mode_octal($collection_root), '0700', 'browser-created sql collection root is owner-only' );
    is( _mode_octal($saved_collection), '0600', 'browser-created sql collection file is owner-only' );
    my $saved_collection_text = _read_text($saved_collection);
    like( $saved_collection_text, qr/"name"\s*:\s*"Shared Queries"/, 'saved sql collection keeps the browser-created collection name' );

    1;
} or do {
    my $error = $@ || 'Playwright sql-dashboard test failed';
    diag $error;
    diag _read_text($dashboard_log) if -f $dashboard_log;
    _stop_dashboard_server(
        cwd           => $project_root,
        home          => $home_root,
        repo_lib      => $repo_lib,
        dashboard_bin => $dashboard_bin,
        pid           => $dashboard_pid,
    ) if $dashboard_pid;
    die $error;
};

_stop_dashboard_server(
    cwd           => $project_root,
    home          => $home_root,
    repo_lib      => $repo_lib,
    dashboard_bin => $dashboard_bin,
    pid           => $dashboard_pid,
) if $dashboard_pid;

done_testing;

sub _playwright_script {
    return <<'JS';
const path = require('path');
const { chromium } = require(path.join(process.env.PLAYWRIGHT_DIR, 'index.js'));

async function main() {
  const browser = await chromium.launch({
    executablePath: process.env.CHROMIUM_BIN,
    headless: true
  });
  const page = await browser.newPage();
  const pageErrors = [];
  const consoleMessages = [];
  page.on('pageerror', (error) => {
    pageErrors.push(String(error && error.stack || error));
  });
  page.on('console', (message) => {
    consoleMessages.push(message.type() + ': ' + message.text());
  });
  await page.goto(process.env.DASHBOARD_URL, { waitUntil: 'networkidle' });
  await page.evaluate(() => {
    const clipboard = {
      writeText: async (value) => {
        window.__sqlDashboardCopiedText = String(value || '');
      }
    };
    try {
      Object.defineProperty(navigator, 'clipboard', { configurable: true, value: clipboard });
    } catch (error) {
      navigator.clipboard = clipboard;
    }
    window.__sqlDashboardCopiedText = '';
  });
  if (pageErrors.length) {
    throw new Error('page errors before interaction: ' + JSON.stringify(pageErrors));
  }

  const driverOptions = await page.locator('#sql-profile-driver option').allTextContents();
  if (!driverOptions.some((value) => String(value || '').includes('DBD::Mock'))) {
    throw new Error('driver dropdown did not expose the installed DBD::Mock module: ' + JSON.stringify(driverOptions));
  }
  await page.locator('#sql-profile-name').fill('Playwright Profile');
  await page.locator('#sql-profile-dsn').fill('dbi:SQLite:playwright');
  await page.locator('#sql-profile-driver').selectOption('DBD::Mock');
  const dsnAfterDriverSelect = await page.locator('#sql-profile-dsn').inputValue();
  if (dsnAfterDriverSelect !== 'dbi:Mock:playwright') {
    throw new Error('driver dropdown did not rewrite the DSN prefix correctly: ' + JSON.stringify({ dsnAfterDriverSelect }));
  }
  await page.locator('#sql-profile-user').fill('play_user');
  await page.locator('#sql-profile-password').fill('play-pass');
  await page.locator('#sql-profile-attrs').fill('{"RaiseError":1,"PrintError":0,"AutoCommit":1}');
  await page.locator('#sql-profile-save-password').check();
  const saveResponse = await Promise.all([
    page.waitForResponse((response) => {
      return response.request().method() === 'POST' &&
        response.url().includes('/ajax/sql-dashboard-profiles-save') && response.status() === 200;
    }),
    page.locator('#sql-profile-save').click()
  ]).then((values) => values[0]);
  const savePayload = await saveResponse.json();
  if (!savePayload || !savePayload.ok) {
    throw new Error('profile save request failed: ' + JSON.stringify(savePayload || {}));
  }
  await page.waitForFunction(() => {



( run in 1.726 second using v1.01-cache-2.11-cpan-39bf76dae61 )