App-karr
view release on metacpan or search on metacpan
t/37-board-render.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use lib 't/lib';
use TestGit qw( require_git_c );
require_git_c();
use File::Temp qw( tempdir );
use YAML::XS qw( Dump );
use App::karr::Git;
use App::karr::BoardStore;
use App::karr::Task;
use App::karr::Cmd::Board;
sub _init_repo {
my $repo = tempdir( CLEANUP => 1 );
system( 'git', 'init', '-q', $repo );
system( 'git', '-C', $repo, 'config', 'user.email', 'test@example.com' );
system( 'git', '-C', $repo, 'config', 'user.name', 'Test User' );
return $repo;
}
my $repo = _init_repo();
my $git = App::karr::Git->new( dir => $repo );
$git->write_ref( 'refs/karr/config', Dump( { version => 1, board => { name => 'My Board' } } ) );
my $store = App::karr::BoardStore->new( git => $git );
sub mk {
my (%a) = @_;
my $t = App::karr::Task->new(
id => $a{id},
title => $a{title},
status => $a{status},
priority => $a{priority} // 'medium',
class => 'standard',
);
$t->due( $a{due} ) if $a{due};
$t->claimed_by( $a{claimed_by} ) if $a{claimed_by};
$t->blocked( $a{blocked} ) if $a{blocked};
$t->tags( $a{tags} ) if $a{tags};
$store->save_task($t);
}
mk( id => 1, title => 'Write documentation', status => 'todo', priority => 'high', due => '2026-07-01' );
mk( id => 2, title => 'Review pull requests', status => 'in-progress', claimed_by => 'getty' );
mk( id => 3, title => 'Fix sync race', status => 'in-progress', priority => 'critical',
claimed_by => 'alice', blocked => 'waiting on libgit2' );
mk( id => 4, title => 'Ship v0.301', status => 'done' );
mk( id => 5, title => 'Tagged task', status => 'todo', tags => [qw( docs urgent )] );
sub render {
my (%opt) = @_;
local $ENV{NO_COLOR} = 1;
my $cmd = App::karr::Cmd::Board->new( store => $store, %opt );
my $buf = '';
{
local *STDOUT;
open STDOUT, '>', \$buf or die $!;
$cmd->execute( [], [] );
}
return $buf;
}
subtest 'default kanban-style rendering' => sub {
my $out = render();
like $out, qr/^# My Board$/m, 'board name as h1';
like $out, qr/^## Todo$/m, 'status header title-cased';
like $out, qr/^## In Progress$/m, 'kebab status -> "In Progress"';
like $out, qr/^## Done$/m, 'empty-ish section still shown';
like $out, qr/^- 1 \| Write documentation \| priority:high \| due:2026-07-01$/m,
'task line: id | title | priority | due';
like $out, qr/^- 2 \| Review pull requests \| \@getty$/m,
'claimed task shows @owner and omits default priority';
unlike $out, qr/priority:medium/, 'medium (default) priority is suppressed';
like $out, qr/^- 3 \| Fix sync race \| priority:critical \| \@alice \| blocked:waiting on libgit2$/m,
'blocked task shows reason';
unlike $out, qr/#docs|#urgent/, 'tags hidden without --tags';
like $out, qr/^5 tasks/m, 'footer counts tasks';
like $out, qr/\bclaimed\b/, 'footer mentions claimed';
like $out, qr/\bblocked\b/, 'footer mentions blocked';
};
subtest '--tags adds an extra tag line' => sub {
my $out = render( tags => 1 );
like $out, qr/^- 5 \| Tagged task$/m, 'tagged task line unchanged';
like $out, qr/^\s+#docs #urgent$/m, 'tags on their own indented line';
};
subtest 'archived empty section is skipped' => sub {
my $out = render();
unlike $out, qr/^## Archived$/m, 'empty archived not shown';
};
done_testing;
( run in 1.425 second using v1.01-cache-2.11-cpan-2398b32b56e )