Add research workspace and graphing flows

This commit is contained in:
2026-03-07 16:52:35 -05:00
parent db01f207a5
commit 62bacdf104
37 changed files with 5494 additions and 434 deletions

View File

@@ -17,14 +17,59 @@ function toSlug(value: string) {
async function signUp(page: Page, testInfo: TestInfo) {
const email = `playwright-research-${testInfo.workerIndex}-${toSlug(testInfo.title)}-${Date.now()}@example.com`;
const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://127.0.0.1:3400';
const output = execFileSync('bun', [
'-e',
`
const [email, password] = process.argv.slice(1);
const { auth } = await import('./lib/auth');
const response = await auth.api.signUpEmail({
body: {
name: 'Playwright Research User',
email,
password,
callbackURL: '/'
},
asResponse: true
});
await page.goto('/auth/signup');
await page.locator('input[autocomplete="name"]').fill('Playwright Research User');
await page.locator('input[autocomplete="email"]').fill(email);
await page.locator('input[autocomplete="new-password"]').first().fill(PASSWORD);
await page.locator('input[autocomplete="new-password"]').nth(1).fill(PASSWORD);
await page.getByRole('button', { name: 'Create account' }).click();
console.log(JSON.stringify({
status: response.status,
sessionCookie: response.headers.get('set-cookie')
}));
`,
email,
PASSWORD
], {
cwd: process.cwd(),
env: {
...process.env,
DATABASE_URL: `file:${E2E_DATABASE_PATH}`,
BETTER_AUTH_BASE_URL: baseURL,
BETTER_AUTH_SECRET: 'playwright-e2e-secret-playwright-e2e-secret',
BETTER_AUTH_TRUSTED_ORIGINS: baseURL
},
encoding: 'utf8'
});
const { status, sessionCookie } = JSON.parse(output) as { status: number; sessionCookie: string | null };
expect(status).toBe(200);
expect(sessionCookie).toBeTruthy();
const [cookieNameValue] = sessionCookie!.split(';');
const separatorIndex = cookieNameValue!.indexOf('=');
const cookieName = cookieNameValue!.slice(0, separatorIndex);
const cookieValue = cookieNameValue!.slice(separatorIndex + 1);
await page.context().addCookies([{
name: cookieName,
value: cookieValue,
url: baseURL,
httpOnly: true,
sameSite: 'Lax'
}]);
await page.goto('/');
await expect(page).toHaveURL(/\/$/);
return email;
}
@@ -109,7 +154,9 @@ finally:
}
test('supports the core coverage-to-research workflow', async ({ page }, testInfo) => {
test.slow();
const accessionNumber = `0001045810-26-${String(Date.now()).slice(-6)}`;
const uploadFixture = join(process.cwd(), 'e2e', 'fixtures', 'sample-research.txt');
await signUp(page, testInfo);
seedFiling({
@@ -139,30 +186,61 @@ test('supports the core coverage-to-research workflow', async ({ page }, testInf
await expect(page).toHaveURL(/\/analysis\?ticker=NVDA/);
await expect(page.getByText('Coverage Workflow')).toBeVisible();
await page.getByLabel('Journal title').fill('Own-the-stack moat check');
await page.getByLabel('Journal body').fill('Monitor hyperscaler concentration, gross margin durability, and Blackwell shipment cadence.');
await page.getByRole('link', { name: 'Open research' }).click();
await expect(page).toHaveURL(/\/research\?ticker=NVDA/);
await page.getByLabel('Research note title').fill('Own-the-stack moat check');
await page.getByLabel('Research note summary').fill('Initial moat checkpoint');
await page.getByLabel('Research note body').fill('Monitor hyperscaler concentration, gross margin durability, and Blackwell shipment cadence.');
await page.getByLabel('Research note tags').fill('moat, thesis');
await page.getByRole('button', { name: 'Save note' }).click();
await expect(page.getByText('Own-the-stack moat check')).toBeVisible();
await expect(page.getByText('Saved note to the research library.')).toBeVisible();
await page.getByLabel('Upload title').fill('Supply-chain diligence');
await page.getByLabel('Upload summary').fill('Vendor and channel-check notes');
await page.getByLabel('Upload tags').fill('diligence, channel-check');
await page.getByLabel('Upload file').setInputFiles(uploadFixture);
await page.locator('button', { hasText: 'Upload file' }).click();
await expect(page.getByText('Uploaded research file.')).toBeVisible();
await page.goto(`/analysis?ticker=NVDA`);
await page.getByRole('link', { name: 'Open summary' }).first().click();
await expect(page).toHaveURL(/\/analysis\/reports\/NVDA\//);
await page.getByRole('button', { name: 'Add to journal' }).click();
await expect(page.getByText('Saved to the company research journal.')).toBeVisible();
await page.getByRole('button', { name: 'Save to library' }).click();
await expect(page.getByText('Saved to the company research library.')).toBeVisible();
await page.getByRole('link', { name: 'Back to analysis' }).click();
await page.goto('/research?ticker=NVDA');
await page.waitForLoadState('networkidle');
await expect(page).toHaveURL(/\/research\?ticker=NVDA/);
await expect(page.getByRole('heading', { name: '10-K AI memo' }).first()).toBeVisible();
await page.getByLabel('Memo rating').selectOption('buy');
await page.getByLabel('Memo conviction').selectOption('high');
await page.getByLabel('Memo time horizon').fill('24');
await page.getByLabel('Packet title').fill('NVIDIA buy-side packet');
await page.getByLabel('Packet subtitle').fill('AI infrastructure compounder');
await page.getByLabel('Memo Thesis').fill('Maintain a constructive stance as datacenter demand and platform depth widen the moat.');
await page.getByLabel('Memo Catalysts').fill('Blackwell ramp, enterprise inference demand, and sustained operating leverage.');
await page.getByLabel('Memo Risks').fill('Customer concentration, competition, and execution on supply.');
await page.getByRole('button', { name: 'Save memo' }).click();
await expect(page.getByText('Saved investment memo.')).toBeVisible();
await page.getByRole('button', { name: 'Attach' }).first().click();
await expect(page.getByText('Attached evidence to Thesis.')).toBeVisible();
await page.goto('/analysis?ticker=NVDA');
await expect(page).toHaveURL(/\/analysis\?ticker=NVDA/);
await expect(page.getByText('10-K AI memo')).toBeVisible();
await page.getByRole('link', { name: 'Open financials' }).click();
await page.goto('/financials?ticker=NVDA');
await expect(page).toHaveURL(/\/financials\?ticker=NVDA/);
await page.getByRole('link', { name: 'Filings' }).first().click();
await page.goto('/filings?ticker=NVDA');
await expect(page).toHaveURL(/\/filings\?ticker=NVDA/);
await expect(page.getByRole('cell', { name: 'NVIDIA Corporation' })).toBeVisible();
await expect(page.getByRole('button', { name: /journal/i }).first()).toBeVisible();
await expect(page.getByRole('link', { name: 'Summary' }).first()).toBeVisible();
});
test('supports add, edit, and delete holding flows with summary refresh', async ({ page }, testInfo) => {
test.slow();
await signUp(page, testInfo);
await page.goto('/portfolio');