Skip to content

Commit f6b34fb

Browse files
authored
Merge pull request #9 from AlekShu/bb-f36d
Reject duplicate documents on upload
2 parents 31797f2 + 73532df commit f6b34fb

16 files changed

Lines changed: 659 additions & 45 deletions

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,34 @@ jobs:
8787
- name: Audit production dependencies
8888
run: npm audit --omit=dev --audit-level=critical
8989

90+
e2e:
91+
name: Run E2E
92+
runs-on: ubuntu-latest
93+
94+
steps:
95+
- name: Checkout code
96+
uses: actions/checkout@v4
97+
98+
- name: Setup Node.js
99+
uses: actions/setup-node@v4
100+
with:
101+
node-version: '20'
102+
cache: 'npm'
103+
104+
- name: Install dependencies
105+
run: npm ci
106+
107+
- name: Install Playwright browser
108+
run: npx playwright install --with-deps chromium
109+
110+
- name: Run Playwright tests
111+
run: npm run e2e
112+
113+
- name: Upload Playwright report
114+
if: always()
115+
uses: actions/upload-artifact@v4
116+
with:
117+
name: playwright-report
118+
path: |
119+
playwright-report
120+
test-results

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ dist-ssr
66

77
.DS_Store
88

9+
# Playwright
10+
/playwright-report/
11+
/test-results/
12+
/blob-report/
13+
/playwright/.cache/
14+
915
*.log
1016
npm-debug.log*
1117
yarn-debug.log*

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## Verification Defaults
2+
3+
- After every code update, run the default verification set: `npm run lint`, `npm run typecheck`, `npm test`.
4+
- For UI-affecting changes, also run `npm run e2e` or an equivalent live UI smoke check against the current dev server.
5+
- Use Spur sidecars for local runtime checks by default.
6+

e2e/duplicate-documents.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { createHash } from 'node:crypto'
2+
import { readFileSync } from 'node:fs'
3+
import path from 'node:path'
4+
5+
import { expect, test } from '@playwright/test'
6+
7+
declare global {
8+
interface Window {
9+
__bloodboyE2E?: {
10+
reset(): Promise<void>
11+
seedExactFileDuplicateScenario(fileHash: string): Promise<void>
12+
}
13+
}
14+
}
15+
16+
const fixturePath = path.join(process.cwd(), 'e2e/fixtures/exact-duplicate.pdf')
17+
const fixtureHash = createHash('sha256').update(readFileSync(fixturePath)).digest('hex')
18+
19+
test.beforeEach(async ({ page }) => {
20+
await page.goto('/data')
21+
await page.waitForFunction(() => typeof window.__bloodboyE2E !== 'undefined')
22+
})
23+
24+
test('excludes an identical file on upload with a notification', async ({ page }) => {
25+
await page.evaluate(async (fileHash) => {
26+
await window.__bloodboyE2E?.seedExactFileDuplicateScenario(fileHash)
27+
}, fixtureHash)
28+
29+
await page.reload()
30+
await page.locator('input[name="file"]').setInputFiles(fixturePath)
31+
32+
await expect(page.getByText('File excluded as duplicate')).toBeVisible()
33+
await expect(page.getByText('is identical to a file you already uploaded')).toBeVisible()
34+
35+
// The duplicate file is not added: the files list still shows only the seeded document.
36+
await page.getByRole('tab', { name: 'Files' }).click()
37+
await expect(page.getByRole('gridcell', { name: 'exact-duplicate.pdf' })).toHaveCount(1)
38+
})

e2e/fixtures/exact-duplicate.pdf

332 Bytes
Binary file not shown.

package-lock.json

Lines changed: 65 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"preview": "vite preview",
5151
"test": "vitest run",
5252
"test:watch": "vitest",
53-
"test:ui": "vitest --ui"
53+
"test:ui": "vitest --ui",
54+
"e2e": "playwright test",
55+
"e2e:ui": "playwright test --ui"
5456
},
5557
"dependencies": {
5658
"@ag-grid-community/client-side-row-model": "32.3.9",
@@ -85,6 +87,7 @@
8587
"zod-error": "2.0.0"
8688
},
8789
"devDependencies": {
90+
"@playwright/test": "1.59.1",
8891
"@svgr/plugin-jsx": "8.1.0",
8992
"@svgr/plugin-svgo": "8.1.0",
9093
"@tanstack/eslint-plugin-query": "5.91.2",
@@ -113,8 +116,8 @@
113116
"tailwindcss": "3.4.17",
114117
"typescript": "5.9.3",
115118
"vite": "6.4.0",
116-
"vitest": "2.1.8",
117119
"vite-plugin-svgr": "4.5.0",
118-
"vite-tsconfig-paths": "5.1.4"
120+
"vite-tsconfig-paths": "5.1.4",
121+
"vitest": "2.1.8"
119122
}
120123
}

playwright.config.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
3+
const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://127.0.0.1:4173'
4+
5+
export default defineConfig({
6+
testDir: './e2e',
7+
fullyParallel: true,
8+
forbidOnly: !!process.env.CI,
9+
retries: process.env.CI ? 2 : 0,
10+
workers: process.env.CI ? 1 : undefined,
11+
reporter: [
12+
['list'],
13+
['html', {
14+
open: 'never',
15+
outputFolder: 'playwright-report',
16+
}],
17+
],
18+
use: {
19+
baseURL,
20+
trace: 'retain-on-failure',
21+
screenshot: 'only-on-failure',
22+
video: 'retain-on-failure',
23+
},
24+
webServer: process.env.PLAYWRIGHT_BASE_URL
25+
? undefined
26+
: {
27+
command: 'npm run dev -- --host 127.0.0.1 --port 4173',
28+
url: baseURL,
29+
reuseExistingServer: !process.env.CI,
30+
timeout: 120000,
31+
},
32+
projects: [
33+
{
34+
name: 'chromium',
35+
use: {
36+
...devices['Desktop Chrome'],
37+
},
38+
},
39+
],
40+
})

0 commit comments

Comments
 (0)