|
| 1 | +import { test, expect } from '@playwright/test' |
| 2 | +import * as fs from 'fs' |
| 3 | +import * as path from 'path' |
| 4 | +import * as os from 'os' |
| 5 | +import { clickOutside } from '../helpers' |
| 6 | + |
| 7 | +const __dirname = import.meta.dirname |
| 8 | + |
| 9 | +/** |
| 10 | + * Generate a file where a \r byte falls exactly at the chunk boundary. |
| 11 | + */ |
| 12 | +function generateFileWithCRLFAtChunkBoundary(filePath: string, chunkSize: number): void { |
| 13 | + const buffer = Buffer.alloc(chunkSize + 1000, 'a') |
| 14 | + buffer[chunkSize - 1] = 0x0D // \r at end of first chunk |
| 15 | + fs.writeFileSync(filePath, buffer) |
| 16 | +} |
| 17 | + |
| 18 | +test('can upload a large file with CRLF at chunk boundary (chunked upload)', async ({ page }) => { |
| 19 | + const chunkSize = 2 * 1000 * 1000 // 2MB |
| 20 | + const tempDir = os.tmpdir() |
| 21 | + const testFilePath = path.join(tempDir, 'test-chunked-upload.csv') |
| 22 | + const uniqueTitle = `Test chunked upload CRLF ${Date.now()}` |
| 23 | + |
| 24 | + generateFileWithCRLFAtChunkBoundary(testFilePath, chunkSize) |
| 25 | + |
| 26 | + await page.goto('/') |
| 27 | + await page.getByRole('button', { name: 'Publier sur data.gouv.fr' }).click() |
| 28 | + await page.getByRole('link', { name: 'Un jeu de données' }).click() |
| 29 | + await page.getByRole('button', { name: 'Commencer la publication' }).click() |
| 30 | + await page.getByTestId('producer-select').click() |
| 31 | + await page.getByRole('option', { name: 'Admin User' }).click() |
| 32 | + await page.getByRole('textbox', { name: 'Titre *' }).fill(uniqueTitle) |
| 33 | + await page.getByTestId('markdown-editor').fill('Test dataset for chunked upload with CRLF line endings.') |
| 34 | + await page.getByTestId('markdown-editor').press('Tab') |
| 35 | + await page.getByText('Il est recommandé d\'avoir une').click() |
| 36 | + await page.getByTestId('select-frequency').click() |
| 37 | + await page.getByRole('option', { name: 'Inconnu' }).click() |
| 38 | + await clickOutside(page) |
| 39 | + await page.getByRole('button', { name: 'Suivant' }).click() |
| 40 | + |
| 41 | + // Upload the large file |
| 42 | + await page.getByRole('button', { name: 'Ajoutez des fichiers' }).click() |
| 43 | + const fileChooserPromise = page.waitForEvent('filechooser') |
| 44 | + await page.getByRole('button', { name: 'Parcourir' }).click() |
| 45 | + const fileChooser = await fileChooserPromise |
| 46 | + await fileChooser.setFiles(testFilePath) |
| 47 | + |
| 48 | + await page.getByRole('button', { name: 'Envoyer' }).click() |
| 49 | + await page.getByRole('button', { name: 'Suivant' }).click() |
| 50 | + |
| 51 | + // Wait for upload to complete |
| 52 | + await page.waitForLoadState('networkidle') |
| 53 | + await page.waitForTimeout(500) |
| 54 | + |
| 55 | + // Verify no chunk size mismatch error |
| 56 | + await expect(page.getByText('Chunk size mismatch')).not.toBeVisible() |
| 57 | + |
| 58 | + // Go to the dataset page and verify the file is present |
| 59 | + await page.getByRole('link', { name: uniqueTitle }).click() |
| 60 | + await expect(page.getByText('test-chunked-upload.csv')).toBeVisible() |
| 61 | +}) |
0 commit comments