mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
migrate frontend tests to playwright
tasks spec settings spec manage spec document-detail spec global permissions spec documents-list & dashboard specs tasks network requests settings network requests permissions network requests manage network request bulk-edit network requests Fix specs try to get playwright working on ci rename some specs reconfigure playwright config increase webserver timeout for ci fix report path
This commit is contained in:
61
src-ui/e2e/dashboard/dashboard.spec.ts
Normal file
61
src-ui/e2e/dashboard/dashboard.spec.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR1 = 'e2e/dashboard/requests/api-dashboard1.har'
|
||||
const REQUESTS_HAR2 = 'e2e/dashboard/requests/api-dashboard2.har'
|
||||
const REQUESTS_HAR3 = 'e2e/dashboard/requests/api-dashboard3.har'
|
||||
const REQUESTS_HAR4 = 'e2e/dashboard/requests/api-dashboard4.har'
|
||||
|
||||
test('dashboard inbox link', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await page.getByRole('link', { name: 'Documents in inbox' }).click()
|
||||
await expect(page).toHaveURL(/tags__id__all=9/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/8 documents/)
|
||||
})
|
||||
|
||||
test('dashboard total documents link', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await page.getByRole('link').filter({ hasText: 'Total documents' }).click()
|
||||
await expect(page).toHaveURL(/documents/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/61 documents/)
|
||||
await page.getByRole('button', { name: 'Reset filters' })
|
||||
})
|
||||
|
||||
test('dashboard saved view show all', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await page
|
||||
.locator('app-widget-frame')
|
||||
.filter({ hasText: 'Inbox' })
|
||||
.getByRole('link', { name: 'Show all' })
|
||||
.click()
|
||||
await expect(page).toHaveURL(/view\/7/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/8 documents/)
|
||||
})
|
||||
|
||||
test('dashboard saved view document links', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR4, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await page
|
||||
.locator('app-widget-frame')
|
||||
.filter({ hasText: 'Inbox' })
|
||||
.locator('table')
|
||||
.getByRole('link', { name: /test/ })
|
||||
.first()
|
||||
.click({ position: { x: 0, y: 0 } })
|
||||
await expect(page).toHaveURL(/documents\/310\/details/)
|
||||
})
|
||||
|
||||
test('test slim sidebar', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await page.locator('#sidebarMenu').getByRole('button').click()
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Dashboard' }).getByText('Dashboard')
|
||||
).toBeHidden()
|
||||
await page.locator('#sidebarMenu').getByRole('button').click()
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Dashboard' }).getByText('Dashboard')
|
||||
).toBeVisible()
|
||||
})
|
1323
src-ui/e2e/dashboard/requests/api-dashboard1.har
Normal file
1323
src-ui/e2e/dashboard/requests/api-dashboard1.har
Normal file
File diff suppressed because one or more lines are too long
3333
src-ui/e2e/dashboard/requests/api-dashboard2.har
Normal file
3333
src-ui/e2e/dashboard/requests/api-dashboard2.har
Normal file
File diff suppressed because one or more lines are too long
1389
src-ui/e2e/dashboard/requests/api-dashboard3.har
Normal file
1389
src-ui/e2e/dashboard/requests/api-dashboard3.har
Normal file
File diff suppressed because one or more lines are too long
790
src-ui/e2e/dashboard/requests/api-dashboard4.har
Normal file
790
src-ui/e2e/dashboard/requests/api-dashboard4.har
Normal file
File diff suppressed because one or more lines are too long
124
src-ui/e2e/document-detail/document-detail.spec.ts
Normal file
124
src-ui/e2e/document-detail/document-detail.spec.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR = 'e2e/document-detail/requests/api-document-detail.har'
|
||||
|
||||
test('should activate / deactivate save button when changes are saved', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/')
|
||||
await page.waitForSelector('app-document-detail app-input-text:first-child')
|
||||
await expect(page.getByTitle('Storage path')).toHaveText(/\w+/)
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
|
||||
await page.getByTitle('Storage path').getByTitle('Clear all').click()
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled()
|
||||
})
|
||||
|
||||
test('should warn on unsaved changes', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/')
|
||||
await expect(page.getByTitle('Correspondent')).toHaveText(/\w+/)
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
|
||||
await page.getByTitle('Storage path').getByTitle('Clear all').click()
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled()
|
||||
await page.getByRole('button', { name: 'Close' }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveText(/unsaved changes/)
|
||||
await page.getByRole('button', { name: 'Cancel' }).click()
|
||||
await page.getByRole('link', { name: 'Close all' }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveText(/unsaved changes/)
|
||||
})
|
||||
|
||||
test('should support tab direct navigation', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/details')
|
||||
await expect(page.getByRole('tab', { name: 'Details' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/documents/175/content')
|
||||
await expect(page.getByRole('tab', { name: 'Content' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/documents/175/metadata')
|
||||
await expect(page.getByRole('tab', { name: 'Metadata' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/documents/175/notes')
|
||||
await expect(page.getByRole('tab', { name: 'Notes' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/documents/175/permissions')
|
||||
await expect(page.getByRole('tab', { name: 'Permissions' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
})
|
||||
|
||||
test('should show a mobile preview', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/')
|
||||
await page.setViewportSize({ width: 400, height: 1000 })
|
||||
await expect(page.getByRole('tab', { name: 'Preview' })).toBeVisible()
|
||||
await page.getByRole('tab', { name: 'Preview' }).click()
|
||||
await page.waitForSelector('pdf-viewer')
|
||||
})
|
||||
|
||||
test('should show a list of notes', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/notes')
|
||||
await expect(page.locator('app-document-notes')).toBeVisible()
|
||||
await expect(
|
||||
await page.getByRole('button', {
|
||||
name: /delete note/i,
|
||||
includeHidden: true,
|
||||
})
|
||||
).toHaveCount(4)
|
||||
})
|
||||
|
||||
test('should support note deletion', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/notes')
|
||||
await expect(page.locator('app-document-notes')).toBeVisible()
|
||||
const deletePromise = page.waitForRequest(
|
||||
(request) =>
|
||||
request.method() === 'DELETE' &&
|
||||
request.url().includes('/api/documents/175/notes/')
|
||||
)
|
||||
await page
|
||||
.getByRole('button', { name: /delete note/i, includeHidden: true })
|
||||
.first()
|
||||
.click()
|
||||
await deletePromise
|
||||
})
|
||||
|
||||
test('should support note insertion', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/documents/175/notes')
|
||||
await expect(page.locator('app-document-notes')).toBeVisible()
|
||||
await expect(
|
||||
await page.getByRole('button', {
|
||||
name: /delete note/i,
|
||||
includeHidden: true,
|
||||
})
|
||||
).toHaveCount(4)
|
||||
await page.getByPlaceholder('Enter note').fill('This is a new note')
|
||||
const addPromise = page.waitForRequest((request) => {
|
||||
if (!request.url().includes('/notes/')) {
|
||||
// ignore other requests
|
||||
return true
|
||||
} else {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = data['note'] === 'This is a new note'
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/notes/')
|
||||
)
|
||||
}
|
||||
})
|
||||
await page.getByRole('button', { name: 'Add note' }).click()
|
||||
await addPromise
|
||||
})
|
949
src-ui/e2e/document-detail/requests/api-document-detail.har
Normal file
949
src-ui/e2e/document-detail/requests/api-document-detail.har
Normal file
File diff suppressed because one or more lines are too long
192
src-ui/e2e/document-list/document-list.spec.ts
Normal file
192
src-ui/e2e/document-list/document-list.spec.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR1 = 'e2e/document-list/requests/api-document-list1.har'
|
||||
const REQUESTS_HAR2 = 'e2e/document-list/requests/api-document-list2.har'
|
||||
const REQUESTS_HAR3 = 'e2e/document-list/requests/api-document-list3.har'
|
||||
const REQUESTS_HAR4 = 'e2e/document-list/requests/api-document-list4.har'
|
||||
const REQUESTS_HAR5 = 'e2e/document-list/requests/api-document-list5.har'
|
||||
const REQUESTS_HAR6 = 'e2e/document-list/requests/api-document-list6.har'
|
||||
|
||||
test('basic filtering', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
await page.getByRole('button', { name: 'Tags' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Inbox' }).click()
|
||||
await expect(page).toHaveURL(/tags__id__all=9/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/8 documents/)
|
||||
await page.getByRole('button', { name: 'Document type' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Invoice Test 3' }).click()
|
||||
await expect(page).toHaveURL(/document_type__id__in=1/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/3 documents/)
|
||||
await page.getByRole('button', { name: 'Reset filters' }).first().click()
|
||||
await page.getByRole('button', { name: 'Correspondent' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Test Correspondent 1' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Correspondent 9' }).click()
|
||||
await expect(page).toHaveURL(/correspondent__id__in=12,1/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/7 documents/)
|
||||
await page
|
||||
.locator('app-filter-editor')
|
||||
.getByTitle('Correspondent')
|
||||
.getByText('Exclude')
|
||||
.click()
|
||||
await expect(page).toHaveURL(/correspondent__id__none=12,1/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/54 documents/)
|
||||
// clear button
|
||||
await page.getByRole('button', { name: '2 selected', exact: true }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(/61 documents/)
|
||||
await page.getByRole('button', { name: 'Storage path' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Testing 12' }).click()
|
||||
await expect(page).toHaveURL(/storage_path__id__in=5/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/8 documents/)
|
||||
await page.getByRole('button', { name: 'Reset filters' }).first().click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(/61 documents/)
|
||||
})
|
||||
|
||||
test('text filtering', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
await page.getByRole('textbox').click()
|
||||
await page.getByRole('textbox').fill('test')
|
||||
await expect(page.locator('app-document-list')).toHaveText(/32 documents/)
|
||||
await expect(page).toHaveURL(/title_content=test/)
|
||||
await page.getByRole('button', { name: 'Title & content' }).click()
|
||||
await page.getByRole('button', { name: 'Title', exact: true }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(/9 documents/)
|
||||
await expect(page).toHaveURL(/title__icontains=test/)
|
||||
await page.getByRole('button', { name: 'Title', exact: true }).click()
|
||||
await page.getByRole('button', { name: 'Advanced search' }).click()
|
||||
await expect(page).toHaveURL(/query=test/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/26 documents/)
|
||||
await page.getByRole('button', { name: 'Advanced search' }).click()
|
||||
await page.getByRole('button', { name: 'ASN' }).click()
|
||||
await page.getByRole('textbox').fill('1123')
|
||||
await expect(page).toHaveURL(/archive_serial_number=1123/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/one document/i)
|
||||
await page.locator('select').selectOption('greater')
|
||||
await page.getByRole('textbox').click()
|
||||
await page.getByRole('textbox').fill('1123')
|
||||
await expect(page).toHaveURL(/archive_serial_number__gt=1123/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/5 documents/)
|
||||
await page.locator('select').selectOption('less')
|
||||
await expect(page).toHaveURL(/archive_serial_number__lt=1123/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/0 documents/)
|
||||
await page.locator('select').selectOption('is null')
|
||||
await expect(page).toHaveURL(/archive_serial_number__isnull=1/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/55 documents/)
|
||||
await page.locator('select').selectOption('not null')
|
||||
await expect(page).toHaveURL(/archive_serial_number__isnull=0/)
|
||||
await expect(page.locator('app-document-list')).toHaveText(/6 documents/)
|
||||
})
|
||||
|
||||
test('date filtering', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
await page.getByRole('button', { name: 'Created' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Last 3 months' }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(/one document/i)
|
||||
await page.getByRole('button', { name: 'Created Clear selected' }).click()
|
||||
await page.getByRole('button', { name: 'Created' }).click()
|
||||
await page
|
||||
.getByRole('menuitem', { name: 'After mm/dd/yyyy' })
|
||||
.getByRole('button')
|
||||
.click()
|
||||
await page.getByRole('combobox', { name: 'Select month' }).selectOption('12')
|
||||
await page.getByRole('combobox', { name: 'Select year' }).selectOption('2022')
|
||||
await page.getByText('11', { exact: true }).click()
|
||||
await page.getByRole('button', { name: 'Title & content' }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(/2 documents/)
|
||||
})
|
||||
|
||||
test('sorting', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR4, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'ASN' }).click()
|
||||
await expect(page).toHaveURL(/sort=archive_serial_number/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page
|
||||
.locator('app-page-header')
|
||||
.getByRole('button', { name: 'Correspondent' })
|
||||
.click()
|
||||
await expect(page).toHaveURL(/sort=correspondent__name/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'Title', exact: true }).click()
|
||||
await expect(page).toHaveURL(/sort=title/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page
|
||||
.locator('app-page-header')
|
||||
.getByRole('button', { name: 'Document type' })
|
||||
.click()
|
||||
await expect(page).toHaveURL(/sort=document_type__name/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'Created', exact: true }).click()
|
||||
await expect(page).toHaveURL(/sort=created/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'Added', exact: true }).click()
|
||||
await expect(page).toHaveURL(/sort=added/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'Modified' }).click()
|
||||
await expect(page).toHaveURL(/sort=modified/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.getByRole('button', { name: 'Notes' }).click()
|
||||
await expect(page).toHaveURL(/sort=num_notes/)
|
||||
await page.getByRole('button', { name: 'Sort' }).click()
|
||||
await page.locator('.w-100 > label > .toolbaricon').first().click()
|
||||
await expect(page).not.toHaveURL(/reverse=1/)
|
||||
})
|
||||
|
||||
test('change views', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR5, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
await page.locator('app-page-header label').first().click()
|
||||
await expect(page.locator('app-document-list table')).toBeVisible()
|
||||
await page.locator('app-page-header label').nth(1).click()
|
||||
await expect(page.locator('app-document-card-small').first()).toBeAttached()
|
||||
await page.locator('app-page-header label').nth(2).click()
|
||||
await expect(page.locator('app-document-card-large').first()).toBeAttached()
|
||||
})
|
||||
|
||||
test('bulk edit', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR6, { notFound: 'fallback' })
|
||||
await page.goto('/documents')
|
||||
|
||||
await page.locator('app-document-card-small').nth(0).click()
|
||||
await page
|
||||
.locator('app-document-card-small')
|
||||
.nth(3)
|
||||
.click({
|
||||
modifiers: ['Shift'],
|
||||
})
|
||||
|
||||
await expect(page.locator('app-document-list')).toHaveText(
|
||||
/Selected 4 of 61 documents/i
|
||||
)
|
||||
|
||||
await page.getByRole('button', { name: 'Page' }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(
|
||||
/Selected 50 of 61 documents/i
|
||||
)
|
||||
await page.getByRole('button', { name: 'All' }).click()
|
||||
await expect(page.locator('app-document-list')).toHaveText(
|
||||
/Selected 61 of 61 documents/i
|
||||
)
|
||||
await page.getByRole('button', { name: 'Cancel' }).click()
|
||||
|
||||
await page.locator('app-document-card-small').nth(1).click()
|
||||
await page.locator('app-document-card-small').nth(2).click()
|
||||
|
||||
await page.getByRole('button', { name: 'Tags' }).click()
|
||||
await page.getByRole('menuitem', { name: 'TagWithPartial' }).click()
|
||||
|
||||
await page.getByRole('button', { name: 'Apply' }).click()
|
||||
|
||||
const bulkEditPromise = page.waitForRequest((request) => {
|
||||
const postData = request.postDataJSON()
|
||||
let isValid = postData['method'] == 'modify_tags'
|
||||
isValid = isValid && postData['parameters']['add_tags'].includes(5)
|
||||
return request.url().toString().includes('bulk_edit') && isValid
|
||||
})
|
||||
|
||||
await page.getByRole('button', { name: 'Confirm' }).click()
|
||||
await bulkEditPromise
|
||||
})
|
7111
src-ui/e2e/document-list/requests/api-document-list1.har
Normal file
7111
src-ui/e2e/document-list/requests/api-document-list1.har
Normal file
File diff suppressed because one or more lines are too long
5373
src-ui/e2e/document-list/requests/api-document-list2.har
Normal file
5373
src-ui/e2e/document-list/requests/api-document-list2.har
Normal file
File diff suppressed because one or more lines are too long
3829
src-ui/e2e/document-list/requests/api-document-list3.har
Normal file
3829
src-ui/e2e/document-list/requests/api-document-list3.har
Normal file
File diff suppressed because one or more lines are too long
5403
src-ui/e2e/document-list/requests/api-document-list4.har
Normal file
5403
src-ui/e2e/document-list/requests/api-document-list4.har
Normal file
File diff suppressed because one or more lines are too long
3545
src-ui/e2e/document-list/requests/api-document-list5.har
Normal file
3545
src-ui/e2e/document-list/requests/api-document-list5.har
Normal file
File diff suppressed because one or more lines are too long
3679
src-ui/e2e/document-list/requests/api-document-list6.har
Normal file
3679
src-ui/e2e/document-list/requests/api-document-list6.har
Normal file
File diff suppressed because one or more lines are too long
58
src-ui/e2e/manage/manage.spec.ts
Normal file
58
src-ui/e2e/manage/manage.spec.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR1 = 'e2e/manage/requests/api-manage1.har'
|
||||
const REQUESTS_HAR2 = 'e2e/manage/requests/api-manage2.har'
|
||||
|
||||
test('should show a list of tags with bottom pagination as well', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/tags')
|
||||
await expect(page.getByRole('main')).toHaveText(/26 total tags/i)
|
||||
await expect(await page.locator('ngb-pagination')).toHaveCount(2)
|
||||
})
|
||||
|
||||
test('should show a list of correspondents without bottom pagination', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
|
||||
await page.goto('/correspondents')
|
||||
await expect(page.getByRole('main')).toHaveText(/4 total correspondents/i)
|
||||
await expect(await page.locator('ngb-pagination')).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('should support quick filter Documents button', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/tags')
|
||||
await page
|
||||
.getByRole('row', { name: 'Inbox' })
|
||||
.getByRole('button', { name: 'Documents' })
|
||||
.click()
|
||||
await expect(page).toHaveURL(/tags__id__all=9/)
|
||||
})
|
||||
|
||||
test('should support item editing', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
|
||||
await page.goto('/tags')
|
||||
await page
|
||||
.getByRole('row', { name: 'Inbox' })
|
||||
.getByRole('button', { name: 'Edit' })
|
||||
.click()
|
||||
await expect(page.getByRole('dialog')).toBeVisible()
|
||||
await expect(page.getByLabel('Name')).toHaveValue('Inbox')
|
||||
await page.getByTitle('Color').getByRole('button').click()
|
||||
const color = await page.getByLabel('Color').inputValue()
|
||||
|
||||
const updatePromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = data['color'] === color
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'PUT' &&
|
||||
request.url().includes('/api/tags/9/')
|
||||
)
|
||||
})
|
||||
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await updatePromise
|
||||
})
|
1090
src-ui/e2e/manage/requests/api-manage1.har
Normal file
1090
src-ui/e2e/manage/requests/api-manage1.har
Normal file
File diff suppressed because one or more lines are too long
260
src-ui/e2e/manage/requests/api-manage2.har
Normal file
260
src-ui/e2e/manage/requests/api-manage2.har
Normal file
File diff suppressed because one or more lines are too long
95
src-ui/e2e/permissions/global-permissions.spec.ts
Normal file
95
src-ui/e2e/permissions/global-permissions.spec.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR = 'e2e/permissions/requests/api-global-permissions.har'
|
||||
|
||||
test('should not allow user to edit settings', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached()
|
||||
await page.goto('/settings')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view documents', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(
|
||||
page.locator('nav').getByRole('link', { name: 'Documents' })
|
||||
).not.toBeAttached()
|
||||
await page.goto('/documents')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
await page.goto('/documents/1')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view correspondents', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Correspondents' })
|
||||
).not.toBeAttached()
|
||||
await page.goto('/correspondents')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view tags', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(page.getByRole('link', { name: 'Tags' })).not.toBeAttached()
|
||||
await page.goto('/tags')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view document types', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Document Types' })
|
||||
).not.toBeAttached()
|
||||
await page.goto('/documenttypes')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view storage paths', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Storage Paths' })
|
||||
).not.toBeAttached()
|
||||
await page.goto('/storagepaths')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view logs', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached()
|
||||
await page.goto('/logs')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
||||
|
||||
test('should not allow user to view tasks', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/dashboard')
|
||||
await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached()
|
||||
await page.goto('/tasks')
|
||||
await expect(page.locator('body')).toHaveText(
|
||||
/You don't have permissions to do that/i
|
||||
)
|
||||
})
|
353
src-ui/e2e/permissions/requests/api-global-permissions.har
Normal file
353
src-ui/e2e/permissions/requests/api-global-permissions.har
Normal file
@@ -0,0 +1,353 @@
|
||||
{
|
||||
"log": {
|
||||
"version": "1.2",
|
||||
"creator": {
|
||||
"name": "Playwright",
|
||||
"version": "1.33.0"
|
||||
},
|
||||
"browser": {
|
||||
"name": "chromium",
|
||||
"version": "113.0.5672.53"
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.455Z",
|
||||
"time": 5.787,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/ui_settings/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Encoding", "value": "br" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "385" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "{\"user\":{\"id\":2,\"username\":\"testuser\",\"is_superuser\":false,\"groups\":[]},\"settings\":{\"language\":\"\",\"bulk_edit\":{\"confirmation_dialogs\":true,\"apply_on_close\":false},\"documentListSize\":50,\"dark_mode\":{\"use_system\":false,\"enabled\":\"false\",\"thumb_inverted\":\"true\"},\"theme\":{\"color\":\"#9fbf2f\"},\"document_details\":{\"native_pdf_viewer\":false},\"date_display\":{\"date_locale\":\"\",\"date_format\":\"mediumDate\"},\"notifications\":{\"consumer_new_documents\":true,\"consumer_success\":true,\"consumer_failed\":true,\"consumer_suppress_on_dashboard\":true},\"comments_enabled\":true,\"slim_sidebar\":false,\"update_checking\":{\"enabled\":false,\"backend_setting\":\"default\"},\"saved_views\":{\"warn_on_unsaved_change\":true},\"notes_enabled\":true,\"tour_complete\":true},\"permissions\":[]}"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 5.787 }
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.578Z",
|
||||
"time": 0.566,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/tasks/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "2" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "[]"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 0.566 }
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.578Z",
|
||||
"time": 0.452,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/statistics/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "257" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "{\"documents_total\":61,\"documents_inbox\":8,\"inbox_tag\":9,\"document_file_type_counts\":[{\"mime_type\":\"application/pdf\",\"mime_type_count\":57},{\"mime_type\":\"text/plain\",\"mime_type_count\":3},{\"mime_type\":\"text/csv\",\"mime_type_count\":1}],\"character_count\":2407053}"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 0.452 }
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.691Z",
|
||||
"time": 0.891,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/ui_settings/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Encoding", "value": "br" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "385" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "{\"user\":{\"id\":2,\"username\":\"testuser\",\"is_superuser\":false,\"groups\":[]},\"settings\":{\"language\":\"\",\"bulk_edit\":{\"confirmation_dialogs\":true,\"apply_on_close\":false},\"documentListSize\":50,\"dark_mode\":{\"use_system\":false,\"enabled\":\"false\",\"thumb_inverted\":\"true\"},\"theme\":{\"color\":\"#9fbf2f\"},\"document_details\":{\"native_pdf_viewer\":false},\"date_display\":{\"date_locale\":\"\",\"date_format\":\"mediumDate\"},\"notifications\":{\"consumer_new_documents\":true,\"consumer_success\":true,\"consumer_failed\":true,\"consumer_suppress_on_dashboard\":true},\"comments_enabled\":true,\"slim_sidebar\":false,\"update_checking\":{\"enabled\":false,\"backend_setting\":\"default\"},\"saved_views\":{\"warn_on_unsaved_change\":true},\"notes_enabled\":true,\"tour_complete\":true},\"permissions\":[]}"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 0.891 }
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.739Z",
|
||||
"time": 0.405,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/tasks/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "2" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "[]"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 0.405 }
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2023-05-14T07:16:51.739Z",
|
||||
"time": 0.665,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "http://localhost:8000/api/statistics/",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Accept", "value": "application/json; version=3" },
|
||||
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
|
||||
{ "name": "Accept-Language", "value": "en-US" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Host", "value": "localhost:8000" },
|
||||
{ "name": "Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Referer", "value": "http://localhost:4200/" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
{ "name": "Sec-Fetch-Mode", "value": "cors" },
|
||||
{ "name": "Sec-Fetch-Site", "value": "same-site" },
|
||||
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
|
||||
],
|
||||
"queryString": [],
|
||||
"headersSize": -1,
|
||||
"bodySize": -1
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
|
||||
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
|
||||
{ "name": "Content-Language", "value": "en-us" },
|
||||
{ "name": "Content-Length", "value": "257" },
|
||||
{ "name": "Content-Type", "value": "application/json" },
|
||||
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||
{ "name": "Referrer-Policy", "value": "same-origin" },
|
||||
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
|
||||
{ "name": "X-Api-Version", "value": "3" },
|
||||
{ "name": "X-Content-Type-Options", "value": "nosniff" },
|
||||
{ "name": "X-Frame-Options", "value": "ANY" },
|
||||
{ "name": "X-Version", "value": "1.14.4" }
|
||||
],
|
||||
"content": {
|
||||
"size": -1,
|
||||
"mimeType": "application/json",
|
||||
"text": "{\"documents_total\":61,\"documents_inbox\":8,\"inbox_tag\":9,\"document_file_type_counts\":[{\"mime_type\":\"application/pdf\",\"mime_type_count\":57},{\"mime_type\":\"text/plain\",\"mime_type_count\":3},{\"mime_type\":\"text/csv\",\"mime_type_count\":1}],\"character_count\":2407053}"
|
||||
},
|
||||
"headersSize": -1,
|
||||
"bodySize": -1,
|
||||
"redirectURL": ""
|
||||
},
|
||||
"cache": {},
|
||||
"timings": { "send": -1, "wait": -1, "receive": 0.665 }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter')
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: ['./src/**/*.e2e-spec.ts'],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () {},
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json'),
|
||||
})
|
||||
jasmine.getEnv().addReporter(
|
||||
new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY,
|
||||
},
|
||||
})
|
||||
)
|
||||
},
|
||||
}
|
194
src-ui/e2e/settings/requests/api-settings.har
Normal file
194
src-ui/e2e/settings/requests/api-settings.har
Normal file
File diff suppressed because one or more lines are too long
326
src-ui/e2e/settings/requests/api-settings2.har
Normal file
326
src-ui/e2e/settings/requests/api-settings2.har
Normal file
File diff suppressed because one or more lines are too long
589
src-ui/e2e/settings/requests/api-settings3.har
Normal file
589
src-ui/e2e/settings/requests/api-settings3.har
Normal file
File diff suppressed because one or more lines are too long
165
src-ui/e2e/settings/settings.spec.ts
Normal file
165
src-ui/e2e/settings/settings.spec.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR = 'e2e/settings/requests/api-settings.har'
|
||||
const REQUESTS_HAR2 = 'e2e/settings/requests/api-settings2.har'
|
||||
const REQUESTS_HAR3 = 'e2e/settings/requests/api-settings3.har'
|
||||
|
||||
test('should post settings on save', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings')
|
||||
await page.getByLabel('Use system setting').click()
|
||||
await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
|
||||
const updatePromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = data['settings'] != null
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/api/ui_settings/')
|
||||
)
|
||||
})
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await updatePromise
|
||||
})
|
||||
|
||||
test('should activate / deactivate save button when settings change', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings')
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
|
||||
await page.getByLabel('Use system setting').click()
|
||||
await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled()
|
||||
})
|
||||
|
||||
test('should warn on unsaved changes', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings')
|
||||
await page.getByLabel('Use system setting').click()
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveText(/unsaved changes/)
|
||||
await page.getByRole('button', { name: 'Cancel' }).click()
|
||||
await page.getByLabel('Use system setting').click()
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveCount(0)
|
||||
})
|
||||
|
||||
test('should apply appearance changes when set', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings')
|
||||
await expect(page.locator('body')).toHaveClass(/color-scheme-system/)
|
||||
await page.getByLabel('Use system setting').click()
|
||||
await page.getByLabel('Enable dark mode').click()
|
||||
await expect(page.locator('body')).toHaveClass(/color-scheme-dark/)
|
||||
})
|
||||
|
||||
test('should toggle saved view options when set & saved', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings/savedviews')
|
||||
await page.getByLabel('Show on dashboard').first().click()
|
||||
await page.getByLabel('Show in sidebar').first().click()
|
||||
const updatePromise = page.waitForRequest((request) => {
|
||||
if (!request.url().includes('8')) return true // skip other saved views
|
||||
const data = request.postDataJSON()
|
||||
const isValid =
|
||||
data['show_on_dashboard'] === true && data['show_in_sidebar'] === true
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'PATCH' &&
|
||||
request.url().includes('/api/saved_views/')
|
||||
)
|
||||
})
|
||||
await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await updatePromise
|
||||
})
|
||||
|
||||
test('should support tab direct navigation', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/settings/general')
|
||||
await expect(page.getByRole('tab', { name: 'General' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/settings/notifications')
|
||||
await expect(
|
||||
page.getByRole('tab', { name: 'Notifications' })
|
||||
).toHaveAttribute('aria-selected', 'true')
|
||||
await page.goto('/settings/savedviews')
|
||||
await expect(page.getByRole('tab', { name: 'Saved Views' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/settings/mail')
|
||||
await expect(page.getByRole('tab', { name: 'Mail' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true'
|
||||
)
|
||||
await page.goto('/settings/usersgroups')
|
||||
await expect(
|
||||
page.getByRole('tab', { name: 'Users & Groups' })
|
||||
).toHaveAttribute('aria-selected', 'true')
|
||||
})
|
||||
|
||||
test('should show a list of mail accounts & support creation', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
|
||||
await page.goto('/settings/mail')
|
||||
await expect(
|
||||
page.getByRole('listitem').filter({ hasText: 'imap.gmail.com' })
|
||||
).toHaveCount(1)
|
||||
await expect(
|
||||
page.getByRole('listitem').filter({ hasText: 'imap.domain.com' })
|
||||
).toHaveCount(1)
|
||||
await page.getByRole('button', { name: /Add Account/ }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveCount(1)
|
||||
await page.getByLabel('Name', { exact: true }).fill('Test Account')
|
||||
await page.getByLabel('IMAP Server', { exact: true }).fill('imap.server.com')
|
||||
await page.getByLabel('IMAP Port', { exact: true }).fill('993')
|
||||
await page.getByLabel('Username', { exact: true }).fill('username')
|
||||
await page.getByLabel('Password', { exact: true }).fill('password')
|
||||
const createPromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = data['imap_server'] === 'imap.server.com'
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/api/mail_accounts/')
|
||||
)
|
||||
})
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await createPromise
|
||||
})
|
||||
|
||||
test('should show a list of mail rules & support creation', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
|
||||
await page.goto('/settings/mail')
|
||||
await expect(
|
||||
page.getByRole('listitem').filter({ hasText: 'domain' })
|
||||
).toHaveCount(2)
|
||||
await expect(
|
||||
page.getByRole('listitem').filter({ hasText: 'gmail' })
|
||||
).toHaveCount(2)
|
||||
await page.getByRole('button', { name: /Add Rule/ }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveCount(1)
|
||||
await page.getByLabel('Name', { exact: true }).fill('Test Rule')
|
||||
await page.getByTitle('Account').locator('span').first().click()
|
||||
await page.getByRole('option', { name: 'gmail' }).click()
|
||||
await page.getByLabel('Maximum age (days)').fill('0')
|
||||
const createPromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = data['name'] === 'Test Rule'
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/api/mail_rules/')
|
||||
)
|
||||
})
|
||||
await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await createPromise
|
||||
})
|
@@ -1,25 +0,0 @@
|
||||
import { AppPage } from './app.po'
|
||||
import { browser, logging } from 'protractor'
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage()
|
||||
})
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo()
|
||||
expect(page.getTitleText()).toEqual('paperless-ui app is running!')
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER)
|
||||
expect(logs).not.toContain(
|
||||
jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry)
|
||||
)
|
||||
})
|
||||
})
|
@@ -1,13 +0,0 @@
|
||||
import { browser, by, element } from 'protractor'
|
||||
|
||||
export class AppPage {
|
||||
navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl) as Promise<unknown>
|
||||
}
|
||||
|
||||
getTitleText(): Promise<string> {
|
||||
return element(
|
||||
by.css('app-root .content span')
|
||||
).getText() as Promise<string>
|
||||
}
|
||||
}
|
252
src-ui/e2e/tasks/requests/api-tasks.har
Normal file
252
src-ui/e2e/tasks/requests/api-tasks.har
Normal file
File diff suppressed because one or more lines are too long
71
src-ui/e2e/tasks/tasks.spec.ts
Normal file
71
src-ui/e2e/tasks/tasks.spec.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const REQUESTS_HAR = 'e2e/tasks/requests/api-tasks.har'
|
||||
|
||||
test('should show a list of dismissable tasks in tabs', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/tasks')
|
||||
await expect(page.getByRole('tab', { name: /Failed/ })).toHaveText(/1/)
|
||||
await expect(
|
||||
page.getByRole('cell').filter({ hasText: 'Dismiss' })
|
||||
).toHaveCount(1)
|
||||
await expect(page.getByRole('tab', { name: /Complete/ })).toHaveText(/8/)
|
||||
await page.getByRole('tab', { name: /Complete/ }).click()
|
||||
await expect(
|
||||
page.getByRole('cell').filter({ hasText: 'Dismiss' })
|
||||
).toHaveCount(8)
|
||||
await page.getByRole('tab', { name: /Started/ }).click()
|
||||
await expect(
|
||||
page.getByRole('cell').filter({ hasText: 'Dismiss' })
|
||||
).toHaveCount(0)
|
||||
await page.getByRole('tab', { name: /Queued/ }).click()
|
||||
await expect(
|
||||
page.getByRole('cell').filter({ hasText: 'Dismiss' })
|
||||
).toHaveCount(0)
|
||||
})
|
||||
|
||||
test('should support dismissing tasks', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/tasks')
|
||||
await page.getByRole('tab', { name: /Failed/ }).click()
|
||||
const dismissPromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = Array.isArray(data['tasks']) && data['tasks'].includes(255)
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/api/acknowledge_tasks/')
|
||||
)
|
||||
})
|
||||
await page
|
||||
.getByRole('button', { name: 'Dismiss', exact: true })
|
||||
.first()
|
||||
.click()
|
||||
await dismissPromise
|
||||
})
|
||||
|
||||
test('should support dismiss all tasks', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/tasks')
|
||||
await expect(page.getByRole('button', { name: 'Dismiss all' })).toBeEnabled()
|
||||
await page.getByRole('button', { name: 'Dismiss all' }).click()
|
||||
const dismissPromise = page.waitForRequest((request) => {
|
||||
const data = request.postDataJSON()
|
||||
const isValid = Array.isArray(data['tasks'])
|
||||
return (
|
||||
isValid &&
|
||||
request.method() === 'POST' &&
|
||||
request.url().includes('/api/acknowledge_tasks/')
|
||||
)
|
||||
})
|
||||
await page.getByRole('button', { name: /Dismiss/ }).click()
|
||||
await dismissPromise
|
||||
})
|
||||
|
||||
test('should warn on dismiss all tasks', async ({ page }) => {
|
||||
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
|
||||
await page.goto('/tasks')
|
||||
await expect(page.getByRole('button', { name: 'Dismiss all' })).toBeEnabled()
|
||||
await page.getByRole('button', { name: 'Dismiss all' }).click()
|
||||
await expect(page.getByRole('dialog')).toHaveCount(1)
|
||||
})
|
@@ -1,14 +0,0 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user