Developer-Dashboard
view release on metacpan or search on metacpan
t/25-api-dashboard-large-import-playwright.t view on Meta::CPAN
}
# _read_text($path)
# Purpose: read one text file from disk.
# Input: absolute file path string.
# Output: raw file content string.
sub _read_text {
my ($path) = @_;
open my $fh, '<:raw', $path or die "Unable to read $path: $!";
local $/;
my $text = <$fh>;
close $fh or die "Unable to close $path: $!";
return $text;
}
# _start_dashboard_server(%args)
# Purpose: launch the dashboard web server as a child process for the browser test.
# Input: hash with cwd, home, repo_lib, dashboard_bin, port, and log_file.
# Output: child process pid integer.
sub _start_dashboard_server {
my (%args) = @_;
my $pid = fork();
die "Unable to fork dashboard serve child: $!" if !defined $pid;
if ( !$pid ) {
open STDOUT, '>:raw', $args{log_file} or die "Unable to write $args{log_file}: $!";
open STDERR, '>&STDOUT' or die "Unable to redirect STDERR to dashboard log: $!";
chdir $args{cwd} or die "Unable to chdir to $args{cwd}: $!";
local %ENV = ( %ENV, HOME => $args{home} );
exec( $^X, "-I$args{repo_lib}", $args{dashboard_bin}, 'serve', '--host', '127.0.0.1', '--port', $args{port} )
or die "Unable to exec dashboard serve: $!";
}
return $pid;
}
# _stop_dashboard_server(%args)
# Purpose: stop the dashboard web server cleanly and ensure the child process exits.
# Input: hash with cwd, home, repo_lib, dashboard_bin, and pid.
# Output: none.
sub _stop_dashboard_server {
my (%args) = @_;
eval {
_run_command(
command => [ $^X, "-I$args{repo_lib}", $args{dashboard_bin}, 'stop' ],
cwd => $args{cwd},
env => { HOME => $args{home} },
label => 'dashboard stop',
);
1;
} or do { };
return if !$args{pid};
kill 'TERM', $args{pid} if kill 0, $args{pid};
waitpid( $args{pid}, 0 );
}
# _playwright_script()
# Purpose: return the embedded Node.js Playwright import flow used by this Perl test.
# Input: none.
# Output: JavaScript source text string.
sub _playwright_script {
return <<'JAVASCRIPT';
const fs = require('fs');
const { chromium } = require(process.env.PLAYWRIGHT_DIR);
async function waitForImportBanner(page, collectionName) {
await page.waitForFunction(
(name) => {
const banner = document.querySelector('#api-banner');
return !!(banner && banner.textContent.includes(`Imported Postman collection "${name}".`));
},
collectionName,
{ timeout: 30000 }
);
}
async function main() {
const browser = await chromium.launch({
executablePath: process.env.CHROMIUM_BIN,
headless: true,
args: ['--no-sandbox', '--disable-dev-shm-usage'],
});
const consoleErrors = [];
try {
const context = await browser.newContext();
const page = await context.newPage();
page.on('console', (message) => {
if (message.type() !== 'error') return;
const text = message.text();
if (text === 'Failed to load resource: the server responded with a status of 404 (Not Found)') return;
if (/favicon\.ico/i.test(text)) return;
consoleErrors.push(text);
});
page.on('pageerror', (error) => {
consoleErrors.push(error && error.stack ? error.stack : String(error));
});
await page.goto(process.env.DASHBOARD_URL, { waitUntil: 'domcontentloaded' });
await page.getByRole('tab', { name: 'Collections' }).click();
await page.waitForSelector('#api-collection-tree');
await page.locator('#api-import-file').setInputFiles({
name: process.env.IMPORT_SOURCE_FILE.split(/[\\/]/).pop(),
mimeType: 'application/json',
buffer: fs.readFileSync(process.env.IMPORT_SOURCE_FILE),
});
await waitForImportBanner(page, process.env.COLLECTION_NAME);
if (consoleErrors.length) {
throw new Error(`Browser console errors: ${consoleErrors.join(' | ')}`);
}
process.stdout.write(JSON.stringify({
ok: true,
imported: true,
}));
} finally {
await browser.close();
}
}
main().catch((error) => {
process.stderr.write((error && error.stack ? error.stack : String(error)) + '\n');
( run in 3.570 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )