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 )