Run playwright UI tests

This commit is contained in:
2026-03-06 14:40:43 -05:00
parent 610fce8db3
commit 8e62c66677
37 changed files with 4430 additions and 643 deletions

View File

@@ -0,0 +1,106 @@
import type { Filing } from '@/lib/types';
import type { TaxonomyFact } from '@/lib/server/taxonomy/types';
const METRIC_LOCAL_NAME_PRIORITY = {
revenue: [
'Revenues',
'SalesRevenueNet',
'RevenueFromContractWithCustomerExcludingAssessedTax',
'TotalRevenuesAndOtherIncome'
],
netIncome: ['NetIncomeLoss', 'ProfitLoss'],
totalAssets: ['Assets'],
cash: [
'CashAndCashEquivalentsAtCarryingValue',
'CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents'
],
debtDirect: [
'DebtAndFinanceLeaseLiabilities',
'Debt',
'LongTermDebtAndCapitalLeaseObligations'
],
debtCurrent: [
'DebtCurrent',
'ShortTermBorrowings',
'LongTermDebtCurrent'
],
debtNonCurrent: [
'LongTermDebtNoncurrent',
'LongTermDebt',
'DebtNoncurrent'
]
} as const;
function normalizeDateToEpoch(value: string | null) {
if (!value) {
return Number.NaN;
}
return Date.parse(value);
}
function sameLocalName(left: string, right: string) {
return left.toLowerCase() === right.toLowerCase();
}
function pickPreferredFact(facts: TaxonomyFact[]) {
const ordered = [...facts].sort((left, right) => {
const leftDimensionScore = left.isDimensionless ? 1 : 0;
const rightDimensionScore = right.isDimensionless ? 1 : 0;
if (leftDimensionScore !== rightDimensionScore) {
return rightDimensionScore - leftDimensionScore;
}
const leftDate = normalizeDateToEpoch(left.periodEnd ?? left.periodInstant);
const rightDate = normalizeDateToEpoch(right.periodEnd ?? right.periodInstant);
if (Number.isFinite(leftDate) && Number.isFinite(rightDate) && leftDate !== rightDate) {
return rightDate - leftDate;
}
return Math.abs(right.value) - Math.abs(left.value);
});
return ordered[0] ?? null;
}
function pickBestFact(facts: TaxonomyFact[], localNames: readonly string[]) {
for (const localName of localNames) {
const matches = facts.filter((fact) => sameLocalName(fact.localName, localName));
if (matches.length === 0) {
continue;
}
return pickPreferredFact(matches);
}
return null;
}
function sumIfBoth(left: number | null, right: number | null) {
if (left === null || right === null) {
return null;
}
return left + right;
}
export function deriveTaxonomyMetrics(facts: TaxonomyFact[]): NonNullable<Filing['metrics']> {
const revenue = pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.revenue)?.value ?? null;
const netIncome = pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.netIncome)?.value ?? null;
const totalAssets = pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.totalAssets)?.value ?? null;
const cash = pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.cash)?.value ?? null;
const directDebt = pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.debtDirect)?.value ?? null;
const debt = directDebt ?? sumIfBoth(
pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.debtCurrent)?.value ?? null,
pickBestFact(facts, METRIC_LOCAL_NAME_PRIORITY.debtNonCurrent)?.value ?? null
);
return {
revenue,
netIncome,
totalAssets,
cash,
debt
};
}