Quality / test (push) Canceled after 0s
Add the admin pricing observation and valuation form, secure valuation writes with CSRF, and extend authenticated browser coverage.
85 lines
5.3 KiB
JavaScript
85 lines
5.3 KiB
JavaScript
import { expect, test } from '@playwright/test';
|
|
|
|
const tinyPng = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', 'base64');
|
|
|
|
test('signs in and publishes a listing after adding an inventory image', async ({ page }) => {
|
|
const email = process.env.INITIAL_ADMIN_EMAIL;
|
|
const password = process.env.INITIAL_ADMIN_PASSWORD;
|
|
|
|
test.skip(!email || !password, 'Set INITIAL_ADMIN_EMAIL and INITIAL_ADMIN_PASSWORD for the local authenticated workflow.');
|
|
|
|
await page.goto('/login');
|
|
await page.getByLabel('Email').fill(email);
|
|
await page.getByLabel('Password').fill(password);
|
|
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
await expect(page).toHaveURL(/\/admin$/);
|
|
await expect(page.getByRole('heading', { name: 'Collector workspace' })).toBeVisible();
|
|
await expect(page.getByRole('status', { name: 'Loading inventory...' })).toHaveCount(0);
|
|
await expect(page.getByRole('heading', { name: 'At a glance' })).toBeVisible();
|
|
await expect(page.getByText('Active inventory')).toBeVisible();
|
|
|
|
const category = page.locator('#product-category option').nth(1);
|
|
await expect(category).toBeAttached();
|
|
const productName = `Browser test collectible ${Date.now()}`;
|
|
await page.getByLabel('Name').fill(productName);
|
|
await page.getByLabel('Category').selectOption({ index: 1 });
|
|
await page.getByRole('button', { name: 'Create product' }).click();
|
|
|
|
await expect(page.locator('#inventory-product option').nth(1)).toBeAttached();
|
|
const createdProductId = await page.getByLabel('Product', { exact: true }).locator('option', { hasText: productName }).getAttribute('value');
|
|
await page.getByLabel('Product', { exact: true }).selectOption(createdProductId);
|
|
await page.getByLabel('Condition', { exact: true }).selectOption({ index: 1 });
|
|
await page.getByRole('button', { name: 'Create copy' }).click();
|
|
|
|
const createdInventoryRow = page.locator(`section[aria-labelledby="inventory-title"] li[data-product-id="${createdProductId}"]`).last();
|
|
const createdInventoryId = await createdInventoryRow.locator('a').getAttribute('href').then((href) => href.split('/').at(-2));
|
|
const inventoryLink = page.locator(`a[href="/admin/inventory/${createdInventoryId}/images"]`);
|
|
await expect(inventoryLink).toBeVisible();
|
|
await page.locator('#acquisition-inventory').selectOption(createdInventoryId);
|
|
await page.getByLabel('Method').fill('PURCHASE');
|
|
await page.getByLabel('Acquisition date').fill('2026-09-09');
|
|
await page.getByLabel('Cost (cents)').fill('1000');
|
|
await page.getByLabel('Shipping (cents)').fill('100');
|
|
await page.getByLabel('Tax (cents)').fill('50');
|
|
await page.getByRole('button', { name: 'Record acquisition' }).click();
|
|
await expect(page.locator('section[aria-labelledby="acquisitions-title"] li').first()).toContainText('Basis $11.50');
|
|
await page.locator('#pricing-inventory').selectOption(createdInventoryId);
|
|
await page.getByLabel('Source identifier').fill('browser-price-1');
|
|
await page.getByLabel('Observed price (cents)').fill('2500');
|
|
await page.getByRole('button', { name: 'Add observation and calculate' }).click();
|
|
await expect(page.getByRole('list', { name: 'Market valuations' })).toContainText('Market value $25.00');
|
|
await inventoryLink.click();
|
|
await expect(page).toHaveURL(/\/admin\/inventory\/[^/]+\/images$/);
|
|
await expect(page.getByRole('heading', { name: 'Manage images' })).toBeVisible();
|
|
await page.getByLabel('Add image').setInputFiles({
|
|
name: 'front.png',
|
|
mimeType: 'image/png',
|
|
buffer: tinyPng,
|
|
});
|
|
await expect(page.getByLabel('Alt text')).toHaveValue('front.png');
|
|
|
|
await page.goto('/admin');
|
|
await expect(page.getByRole('heading', { name: 'Create listing draft' })).toBeVisible();
|
|
await page.getByLabel('Inventory copy', { exact: true }).first().selectOption(createdInventoryId);
|
|
await page.getByLabel('Asking price (cents)').fill('2499');
|
|
await page.getByRole('button', { name: 'Create listing' }).click();
|
|
const createdListing = page.locator('section[aria-labelledby="listings-title"] article').filter({ hasText: productName }).last();
|
|
await expect(createdListing.getByText('Add at least one image before publishing.')).toHaveCount(0);
|
|
await createdListing.getByRole('button', { name: 'Publish' }).click();
|
|
await expect(createdListing).toContainText('AVAILABLE');
|
|
|
|
await page.locator('#sale-inventory').selectOption(createdInventoryId);
|
|
await page.getByLabel('Sale date').fill('2026-09-09');
|
|
await page.getByLabel('Sold price (cents)').fill('2499');
|
|
await page.getByLabel('Cost basis (cents)').fill('1200');
|
|
await page.getByRole('button', { name: 'Record sale' }).click();
|
|
await expect(page.locator('section[aria-labelledby="inventory-title"]').getByText(`${createdInventoryId} · SOLD`)).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Sale history' })).toBeVisible();
|
|
const latestSale = page.locator('section[aria-labelledby="sales-title"] li').first();
|
|
await expect(latestSale).toContainText('Profit $12.99');
|
|
await latestSale.getByLabel('Void reason').fill('Browser test correction');
|
|
await latestSale.getByRole('button', { name: 'Void sale' }).click();
|
|
await expect(latestSale).toContainText('VOIDED');
|
|
await expect(page.locator('section[aria-labelledby="inventory-title"]').getByText(`${createdInventoryId} · ACTIVE`)).toBeVisible();
|
|
});
|