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:
shamoon 2023-05-07 21:30:49 -07:00
parent 0baf73de5e
commit 0c6a9a189b
67 changed files with 40971 additions and 4740 deletions

View File

@ -192,10 +192,25 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: 'src-ui/package-lock.json'
- run: cd src-ui && npm ci
- run: cd src-ui && npm run lint
- run: cd src-ui && npm run test
- run: cd src-ui && npm run e2e:ci
-
name: Install dependencies
run: cd src-ui && npm ci
-
name: Install Playwright
run: npx playwright install --with-deps
-
name: Linting checks
run: cd src-ui && npm run lint
-
name: Run Playwright tests
run: cd src-ui && npx playwright test
-
name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: src-ui/playwright-report
build-docker-image:
name: Build Docker image for ${{ github.ref_name }}

3
src-ui/.gitignore vendored
View File

@ -49,3 +49,6 @@ Thumbs.db
# Cypress
cypress/videos/**/*
cypress/screenshots/**/*
/test-results/
/playwright-report/
/playwright/.cache/

View File

@ -147,37 +147,6 @@
"scripts": []
}
},
"e2e": {
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "paperless-ui:serve",
"watch": true,
"headless": false
},
"configurations": {
"production": {
"devServerTarget": "paperless-ui:serve:production"
}
}
},
"cypress-run": {
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "paperless-ui:serve"
},
"configurations": {
"production": {
"devServerTarget": "paperless-ui:serve:production"
}
}
},
"cypress-open": {
"builder": "@cypress/schematic:cypress",
"options": {
"watch": true,
"headless": false
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {

View File

@ -1,14 +0,0 @@
import { defineConfig } from 'cypress'
export default defineConfig({
videosFolder: 'cypress/videos',
video: false,
screenshotsFolder: 'cypress/screenshots',
fixturesFolder: 'cypress/fixtures',
e2e: {
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.ts')(on, config)
},
baseUrl: 'http://localhost:4200',
},
})

View File

@ -1,68 +0,0 @@
describe('settings', () => {
beforeEach(() => {
// also uses global fixtures from cypress/support/e2e.ts
// mock restricted permissions
cy.intercept('http://localhost:8000/api/ui_settings/', {
fixture: 'ui_settings/settings_restricted.json',
})
})
it('should not allow user to edit settings', () => {
cy.visit('/dashboard')
cy.contains('Settings').should('not.exist')
cy.visit('/settings').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view documents', () => {
cy.visit('/dashboard')
cy.contains('Documents').should('not.exist')
cy.visit('/documents').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
cy.visit('/documents/1').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view correspondents', () => {
cy.visit('/dashboard')
cy.contains('Correspondents').should('not.exist')
cy.visit('/correspondents').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view tags', () => {
cy.visit('/dashboard')
cy.contains('Tags').should('not.exist')
cy.visit('/tags').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view document types', () => {
cy.visit('/dashboard')
cy.contains('Document Types').should('not.exist')
cy.visit('/documenttypes').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view storage paths', () => {
cy.visit('/dashboard')
cy.contains('Storage Paths').should('not.exist')
cy.visit('/storagepaths').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view logs', () => {
cy.visit('/dashboard')
cy.contains('Logs').should('not.exist')
cy.visit('/logs').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
it('should not allow user to view tasks', () => {
cy.visit('/dashboard')
cy.contains('Tasks').should('not.exist')
cy.visit('/tasks').wait(2000)
cy.contains("You don't have permissions to do that").should('exist')
})
})

View File

@ -1,118 +0,0 @@
describe('document-detail', () => {
beforeEach(() => {
// also uses global fixtures from cypress/support/e2e.ts
this.modifiedDocuments = []
cy.fixture('documents/documents.json').then((documentsJson) => {
cy.intercept(
'GET',
'http://localhost:8000/api/documents/1/?full_perms=true',
(req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
}
)
})
cy.intercept('PUT', 'http://localhost:8000/api/documents/1/', (req) => {
this.modifiedDocuments.push(req.body) // store this for later
req.reply({ result: 'OK' })
}).as('saveDoc')
cy.fixture('documents/1/notes.json').then((notesJson) => {
cy.intercept(
'GET',
'http://localhost:8000/api/documents/1/notes/',
(req) => {
req.reply(notesJson.filter((c) => c.id != 10)) // 3
}
)
cy.intercept(
'DELETE',
'http://localhost:8000/api/documents/1/notes/?id=9',
(req) => {
req.reply(notesJson.filter((c) => c.id != 9 && c.id != 10)) // 2
}
)
cy.intercept(
'POST',
'http://localhost:8000/api/documents/1/notes/',
(req) => {
req.reply(notesJson) // 4
}
)
})
cy.viewport(1024, 1024)
cy.visit('/documents/1/').wait('@ui-settings')
})
it('should activate / deactivate save button when changes are saved', () => {
cy.contains('button', 'Save').should('be.disabled')
cy.get('app-input-text[formcontrolname="title"]')
.type(' additional')
.wait(1500) // this delay is for frontend debounce
cy.contains('button', 'Save').should('not.be.disabled')
})
it('should warn on unsaved changes', () => {
cy.get('app-input-text[formcontrolname="title"]')
.type(' additional')
.wait(1500) // this delay is for frontend debounce
cy.get('button[title="Close"]').click()
cy.contains('You have unsaved changes')
cy.contains('button', 'Cancel').click().wait(150)
cy.contains('button', 'Save').click().wait('@saveDoc').wait(2000) // navigates away after saving
cy.contains('You have unsaved changes').should('not.exist')
})
it('should show a mobile preview', () => {
cy.viewport(440, 1000)
cy.get('a')
.contains('Preview')
.scrollIntoView({ offset: { top: 150, left: 0 } })
.click()
cy.get('pdf-viewer').should('be.visible')
})
it('should show a list of notes', () => {
cy.wait(1000).get('a').contains('Notes').click({ force: true }).wait(1000)
cy.get('app-document-notes').find('.card').its('length').should('eq', 3)
})
it('should support note deletion', () => {
cy.wait(1000).get('a').contains('Notes').click().wait(1000)
cy.get('app-document-notes')
.find('.card')
.first()
.find('button')
.click({ force: true })
.wait(500)
cy.get('app-document-notes').find('.card').its('length').should('eq', 2)
})
it('should support note insertion', () => {
cy.wait(1000).get('a').contains('Notes').click().wait(1000)
cy.get('app-document-notes')
.find('form textarea')
.type('Testing new note')
.wait(500)
cy.get('app-document-notes').find('form button').click().wait(1500)
cy.get('app-document-notes').find('.card').its('length').should('eq', 4)
})
it('should support navigation to notes tab by url', () => {
cy.visit('/documents/1/notes')
cy.get('app-document-notes').should('exist')
})
it('should dynamically update note counts', () => {
cy.visit('/documents/1/notes')
cy.get('app-document-notes').within(() => cy.contains('Delete').click())
cy.get('ul.nav').find('li').contains('Notes').find('.badge').contains('2')
})
})

View File

@ -1,196 +0,0 @@
describe('documents-list', () => {
beforeEach(() => {
// also uses global fixtures from cypress/support/e2e.ts
this.bulkEdits = {}
cy.fixture('documents/documents.json').then((documentsJson) => {
// bulk edit
cy.intercept(
'POST',
'http://localhost:8000/api/documents/bulk_edit/',
(req) => {
this.bulkEdits = req.body // store this for later
req.reply({ result: 'OK' })
}
)
cy.intercept('GET', 'http://localhost:8000/api/documents/*', (req) => {
let response = { ...documentsJson }
// bulkEdits was set earlier by bulk_edit intercept
if (this.bulkEdits.hasOwnProperty('documents')) {
response.results = response.results.map((d) => {
if ((this.bulkEdits['documents'] as Array<number>).includes(d.id)) {
switch (this.bulkEdits['method']) {
case 'modify_tags':
d.tags = (d.tags as Array<number>).concat([
this.bulkEdits['parameters']['add_tags'],
])
break
case 'set_correspondent':
d.correspondent =
this.bulkEdits['parameters']['correspondent']
break
case 'set_document_type':
d.document_type =
this.bulkEdits['parameters']['document_type']
break
}
}
return d
})
} else if (req.query.hasOwnProperty('tags__id__all')) {
// filtering e.g. http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&tags__id__all=2
const tag_id = +req.query['tags__id__all']
response.results = (documentsJson.results as Array<any>).filter((d) =>
(d.tags as Array<number>).includes(tag_id)
)
response.count = response.results.length
} else if (req.query.hasOwnProperty('correspondent__id__in')) {
// filtering e.g. http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&correspondent__id__in=9,14
const correspondent_ids = req.query['correspondent__id__in']
.toString()
.split(',')
.map((c) => +c)
response.results = (documentsJson.results as Array<any>).filter((d) =>
correspondent_ids.includes(d.correspondent)
)
response.count = response.results.length
} else if (req.query.hasOwnProperty('correspondent__id__none')) {
// filtering e.g. http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&correspondent__id__none=9,14
const correspondent_ids = req.query['correspondent__id__none']
.toString()
.split(',')
.map((c) => +c)
response.results = (documentsJson.results as Array<any>).filter(
(d) => !correspondent_ids.includes(d.correspondent)
)
response.count = response.results.length
}
req.reply(response)
})
cy.intercept('http://localhost:8000/api/documents/selection_data/', {
fixture: 'documents/selection_data.json',
}).as('selection-data')
})
cy.viewport(1280, 1024)
cy.visit('/documents')
})
it('should show a list of documents rendered as cards with thumbnails', () => {
cy.contains('3 documents')
cy.contains('lorem ipsum')
cy.get('app-document-card-small:first-of-type img')
.invoke('attr', 'src')
.should('eq', 'http://localhost:8000/api/documents/1/thumb/')
})
it('should change to table "details" view', () => {
cy.get('div.btn-group input[value="details"]').next().click()
cy.get('table')
})
it('should change to large cards view', () => {
cy.get('div.btn-group input[value="largeCards"]').next().click()
cy.get('app-document-card-large')
})
it('should show partial tag selection', () => {
cy.get('app-document-card-small:nth-child(1)').click()
cy.get('app-document-card-small:nth-child(4)').click()
cy.get('app-bulk-editor button')
.contains('Tags')
.click()
.wait('@selection-data')
cy.get('svg.bi-dash').should('be.visible')
cy.get('svg.bi-check').should('be.visible')
})
it('should allow bulk removal', () => {
cy.get('app-document-card-small:nth-child(1)').click()
cy.get('app-document-card-small:nth-child(4)').click()
cy.get('app-bulk-editor').within(() => {
cy.get('button').contains('Tags').click().wait('@selection-data')
cy.get('button').contains('Another Sample Tag').click()
cy.get('button').contains('Apply').click()
})
cy.contains('operation will remove the tag')
})
it('should filter tags', () => {
cy.get('app-filter-editor app-filterable-dropdown[title="Tags"]').within(
() => {
cy.contains('button', 'Tags').click()
cy.contains('button', 'Tag 2').click()
}
)
cy.contains('One document')
})
it('should filter including multiple correspondents', () => {
cy.get('app-filter-editor app-filterable-dropdown[title="Correspondent"]')
.click()
.within(() => {
cy.contains('button', 'ABC Test Correspondent').click()
cy.contains('button', 'Corresp 11').click()
})
cy.contains('3 documents')
})
it('should filter excluding multiple correspondents', () => {
cy.get('app-filter-editor app-filterable-dropdown[title="Correspondent"]')
.click()
.within(() => {
cy.contains('button', 'ABC Test Correspondent').click()
cy.contains('button', 'Corresp 11').click()
cy.contains('label', 'Exclude').click()
})
cy.contains('3 documents')
})
it('should apply tags', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get('app-bulk-editor app-filterable-dropdown[title="Tags"]').within(
() => {
cy.contains('button', 'Tags').click()
cy.contains('button', 'Test Tag').click()
cy.contains('button', 'Apply').click()
}
)
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains('Test Tag')
})
it('should apply correspondent', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get(
'app-bulk-editor app-filterable-dropdown[title="Correspondent"]'
).within(() => {
cy.contains('button', 'Correspondent').click()
cy.contains('button', 'ABC Test Correspondent').click()
cy.contains('button', 'Apply').click()
})
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains(
'ABC Test Correspondent'
)
})
it('should apply document type', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get(
'app-bulk-editor app-filterable-dropdown[title="Document type"]'
).within(() => {
cy.contains('button', 'Document type').click()
cy.contains('button', 'Test Doc Type').click()
cy.contains('button', 'Apply').click()
})
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains('Test Doc Type')
})
})

View File

@ -1,391 +0,0 @@
import { PaperlessDocument } from 'src/app/data/paperless-document'
describe('documents query params', () => {
beforeEach(() => {
// also uses global fixtures from cypress/support/e2e.ts
cy.fixture('documents/documents.json').then((documentsJson) => {
// mock api filtering
cy.intercept('GET', 'http://localhost:8000/api/documents/*', (req) => {
let response = { ...documentsJson }
if (req.query.hasOwnProperty('ordering')) {
const sort_field = req.query['ordering'].toString().replace('-', '')
const reverse = req.query['ordering'].toString().indexOf('-') !== -1
response.results = (
documentsJson.results as Array<PaperlessDocument>
).sort((docA, docB) => {
let result = 0
switch (sort_field) {
case 'created':
case 'added':
result =
new Date(docA[sort_field]) < new Date(docB[sort_field])
? -1
: 1
break
case 'archive_serial_number':
result = docA[sort_field] < docB[sort_field] ? -1 : 1
break
}
if (reverse) result = -result
return result
})
}
if (req.query.hasOwnProperty('tags__id__in')) {
const tag_ids: Array<number> = req.query['tags__id__in']
.toString()
.split(',')
.map((v) => +v)
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter(
(d) =>
d.tags.length > 0 &&
d.tags.filter((t) => tag_ids.includes(t)).length > 0
)
response.count = response.results.length
} else if (req.query.hasOwnProperty('tags__id__none')) {
const tag_ids: Array<number> = req.query['tags__id__none']
.toString()
.split(',')
.map((v) => +v)
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.tags.filter((t) => tag_ids.includes(t)).length == 0)
response.count = response.results.length
} else if (
req.query.hasOwnProperty('is_tagged') &&
req.query['is_tagged'] == '0'
) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.tags.length == 0)
response.count = response.results.length
}
if (req.query.hasOwnProperty('document_type__id')) {
const doctype_id = +req.query['document_type__id']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.document_type == doctype_id)
response.count = response.results.length
} else if (
req.query.hasOwnProperty('document_type__isnull') &&
req.query['document_type__isnull'] == '1'
) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.document_type == undefined)
response.count = response.results.length
}
if (req.query.hasOwnProperty('correspondent__id')) {
const correspondent_id = +req.query['correspondent__id']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.correspondent == correspondent_id)
response.count = response.results.length
} else if (
req.query.hasOwnProperty('correspondent__isnull') &&
req.query['correspondent__isnull'] == '1'
) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.correspondent == undefined)
response.count = response.results.length
}
if (req.query.hasOwnProperty('storage_path__id')) {
const storage_path_id = +req.query['storage_path__id']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.storage_path == storage_path_id)
response.count = response.results.length
} else if (
req.query.hasOwnProperty('storage_path__isnull') &&
req.query['storage_path__isnull'] == '1'
) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.storage_path == undefined)
response.count = response.results.length
}
if (req.query.hasOwnProperty('created__date__gt')) {
const date = new Date(req.query['created__date__gt'])
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => new Date(d.created) > date)
response.count = response.results.length
} else if (req.query.hasOwnProperty('created__date__lt')) {
const date = new Date(req.query['created__date__lt'])
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => new Date(d.created) < date)
response.count = response.results.length
}
if (req.query.hasOwnProperty('added__date__gt')) {
const date = new Date(req.query['added__date__gt'])
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => new Date(d.added) > date)
response.count = response.results.length
} else if (req.query.hasOwnProperty('added__date__lt')) {
const date = new Date(req.query['added__date__lt'])
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => new Date(d.added) < date)
response.count = response.results.length
}
if (req.query.hasOwnProperty('title_content')) {
const title_content_regexp = new RegExp(
req.query['title_content'].toString(),
'i'
)
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter(
(d) =>
title_content_regexp.test(d.title) ||
title_content_regexp.test(d.content)
)
response.count = response.results.length
}
if (req.query.hasOwnProperty('archive_serial_number')) {
const asn = +req.query['archive_serial_number']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.archive_serial_number == asn)
response.count = response.results.length
} else if (req.query.hasOwnProperty('archive_serial_number__isnull')) {
const isnull = req.query['storage_path__isnull'] == '1'
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) =>
isnull
? d.archive_serial_number == undefined
: d.archive_serial_number != undefined
)
response.count = response.results.length
} else if (req.query.hasOwnProperty('archive_serial_number__gt')) {
const asn = +req.query['archive_serial_number__gt']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter(
(d) => d.archive_serial_number > 0 && d.archive_serial_number > asn
)
response.count = response.results.length
} else if (req.query.hasOwnProperty('archive_serial_number__lt')) {
const asn = +req.query['archive_serial_number__lt']
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter(
(d) => d.archive_serial_number > 0 && d.archive_serial_number < asn
)
response.count = response.results.length
}
if (req.query.hasOwnProperty('owner__id')) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.owner == req.query['owner__id'])
response.count = response.results.length
} else if (req.query.hasOwnProperty('owner__id__in')) {
const owners = req.query['owner__id__in']
.toString()
.split(',')
.map((o) => parseInt(o))
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => owners.includes(d.owner))
response.count = response.results.length
} else if (req.query.hasOwnProperty('owner__id__none')) {
const owners = req.query['owner__id__none']
.toString()
.split(',')
.map((o) => parseInt(o))
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => !owners.includes(d.owner))
response.count = response.results.length
} else if (req.query.hasOwnProperty('owner__isnull')) {
response.results = (
documentsJson.results as Array<PaperlessDocument>
).filter((d) => d.owner === null)
response.count = response.results.length
}
req.reply(response)
})
})
})
it('should show a list of documents sorted by created', () => {
cy.visit('/documents?sort=created')
cy.get('app-document-card-small').first().contains('No latin title')
})
it('should show a list of documents reverse sorted by created', () => {
cy.visit('/documents?sort=created&reverse=true')
cy.get('app-document-card-small').first().contains('Doc 6')
})
it('should show a list of documents sorted by added', () => {
cy.visit('/documents?sort=added')
cy.get('app-document-card-small').first().contains('No latin title')
})
it('should show a list of documents reverse sorted by added', () => {
cy.visit('/documents?sort=added&reverse=true')
cy.get('app-document-card-small').first().contains('Doc 6')
})
it('should show a list of documents filtered by any tags', () => {
cy.visit('/documents?sort=created&reverse=true&tags__id__in=2,4,5')
cy.contains('3 documents')
})
it('should show a list of documents filtered by excluded tags', () => {
cy.visit('/documents?sort=created&reverse=true&tags__id__none=2,4')
cy.contains('3 documents')
})
it('should show a list of documents filtered by no tags', () => {
cy.visit('/documents?sort=created&reverse=true&is_tagged=0')
cy.contains('3 documents')
})
it('should show a list of documents filtered by document type', () => {
cy.visit('/documents?sort=created&reverse=true&document_type__id=1')
cy.contains('2 documents')
})
it('should show a list of documents filtered by multiple correspondents', () => {
cy.visit('/documents?sort=created&reverse=true&document_type__id__in=1,2')
cy.contains('3 documents')
})
it('should show a list of documents filtered by no document type', () => {
cy.visit('/documents?sort=created&reverse=true&document_type__isnull=1')
cy.contains('3 documents')
})
it('should show a list of documents filtered by correspondent', () => {
cy.visit('/documents?sort=created&reverse=true&correspondent__id=9')
cy.contains('2 documents')
})
it('should show a list of documents filtered by multiple correspondents', () => {
cy.visit('/documents?sort=created&reverse=true&correspondent__id__in=9,14')
cy.contains('3 documents')
})
it('should show a list of documents filtered by no correspondent', () => {
cy.visit('/documents?sort=created&reverse=true&correspondent__isnull=1')
cy.contains('3 documents')
})
it('should show a list of documents filtered by storage path', () => {
cy.visit('/documents?sort=created&reverse=true&storage_path__id=2')
cy.contains('One document')
})
it('should show a list of documents filtered by no storage path', () => {
cy.visit('/documents?sort=created&reverse=true&storage_path__isnull=1')
cy.contains('5 documents')
})
it('should show a list of documents filtered by title or content', () => {
cy.visit('/documents?sort=created&reverse=true&title_content=lorem')
cy.contains('2 documents')
})
it('should show a list of documents filtered by asn', () => {
cy.visit('/documents?sort=created&reverse=true&archive_serial_number=12345')
cy.contains('One document')
})
it('should show a list of documents filtered by empty asn', () => {
cy.visit(
'/documents?sort=created&reverse=true&archive_serial_number__isnull=1'
)
cy.contains('2 documents')
})
it('should show a list of documents filtered by non-empty asn', () => {
cy.visit(
'/documents?sort=created&reverse=true&archive_serial_number__isnull=0'
)
cy.contains('2 documents')
})
it('should show a list of documents filtered by asn greater than', () => {
cy.visit(
'/documents?sort=created&reverse=true&archive_serial_number__gt=12346'
)
cy.contains('One document')
})
it('should show a list of documents filtered by asn less than', () => {
cy.visit(
'/documents?sort=created&reverse=true&archive_serial_number__lt=12346'
)
cy.contains('One document')
})
it('should show a list of documents filtered by created date greater than', () => {
cy.visit(
'/documents?sort=created&reverse=true&created__date__gt=2022-03-23'
)
cy.contains('5 documents')
})
it('should show a list of documents filtered by created date less than', () => {
cy.visit(
'/documents?sort=created&reverse=true&created__date__lt=2022-03-23'
)
cy.contains('One document')
})
it('should show a list of documents filtered by added date greater than', () => {
cy.visit('/documents?sort=created&reverse=true&added__date__gt=2022-03-24')
cy.contains('4 documents')
})
it('should show a list of documents filtered by added date less than', () => {
cy.visit('/documents?sort=created&reverse=true&added__date__lt=2022-03-24')
cy.contains('2 documents')
})
it('should show a list of documents filtered by multiple filters', () => {
cy.visit(
'/documents?sort=created&reverse=true&document_type__id=1&correspondent__id=9&tags__id__in=4,5'
)
cy.contains('2 documents')
})
it('should show a list of documents filtered by owner', () => {
cy.visit('/documents?owner__id=15')
cy.contains('One document')
})
it('should show a list of documents filtered by multiple owners', () => {
cy.visit('/documents?owner__id__in=6,15')
cy.contains('2 documents')
})
it('should show a list of documents filtered by excluded owners', () => {
cy.visit('/documents?owner__id__none=6')
cy.contains('5 documents')
})
it('should show a list of documents filtered by null owner', () => {
cy.visit('/documents?owner__isnull=true')
cy.contains('4 documents')
})
})

View File

@ -1,25 +0,0 @@
describe('manage', () => {
// also uses global fixtures from cypress/support/e2e.ts
it('should show a list of correspondents with bottom pagination as well', () => {
cy.visit('/correspondents')
cy.get('tbody').find('tr').its('length').should('eq', 25)
cy.get('ngb-pagination').its('length').should('eq', 2)
})
it('should show a list of tags without bottom pagination', () => {
cy.visit('/tags')
cy.get('tbody').find('tr').its('length').should('eq', 8)
cy.get('ngb-pagination').its('length').should('eq', 1)
})
it('should show a list of documents filtered by tag', () => {
cy.intercept('http://localhost:8000/api/documents/*', (req) => {
if (req.url.indexOf('tags__id__all=4'))
req.reply({ count: 3, next: null, previous: null, results: [] })
})
cy.visit('/tags')
cy.get('tbody').find('button:visible').contains('Documents').first().click() // id = 4
cy.contains('3 documents')
})
})

View File

@ -1,187 +0,0 @@
describe('settings', () => {
beforeEach(() => {
// also uses global fixtures from cypress/support/e2e.ts
this.modifiedViews = []
// mock API methods
cy.intercept('http://localhost:8000/api/ui_settings/', {
fixture: 'ui_settings/settings.json',
}).then(() => {
cy.fixture('saved_views/savedviews.json').then((savedViewsJson) => {
// saved views PATCH
cy.intercept(
'PATCH',
'http://localhost:8000/api/saved_views/*',
(req) => {
this.modifiedViews.push(req.body) // store this for later
req.reply({ result: 'OK' })
}
)
cy.intercept(
'GET',
'http://localhost:8000/api/saved_views/*',
(req) => {
let response = { ...savedViewsJson }
if (this.modifiedViews.length) {
response.results = response.results.map((v) => {
if (this.modifiedViews.find((mv) => mv.id == v.id))
v = this.modifiedViews.find((mv) => mv.id == v.id)
return v
})
}
req.reply(response)
}
).as('savedViews')
})
this.newMailAccounts = []
cy.intercept(
'POST',
'http://localhost:8000/api/mail_accounts/',
(req) => {
const newRule = req.body
newRule.id = 3
this.newMailAccounts.push(newRule) // store this for later
req.reply({ result: 'OK' })
}
).as('saveAccount')
cy.fixture('mail_accounts/mail_accounts.json').then(
(mailAccountsJson) => {
cy.intercept(
'GET',
'http://localhost:8000/api/mail_accounts/*',
(req) => {
let response = { ...mailAccountsJson }
if (this.newMailAccounts.length) {
response.results = response.results.concat(this.newMailAccounts)
}
req.reply(response)
}
).as('getAccounts')
}
)
this.newMailRules = []
cy.intercept('POST', 'http://localhost:8000/api/mail_rules/', (req) => {
const newRule = req.body
newRule.id = 2
this.newMailRules.push(newRule) // store this for later
req.reply({ result: 'OK' })
}).as('saveRule')
cy.fixture('mail_rules/mail_rules.json').then((mailRulesJson) => {
cy.intercept('GET', 'http://localhost:8000/api/mail_rules/*', (req) => {
let response = { ...mailRulesJson }
if (this.newMailRules.length) {
response.results = response.results.concat(this.newMailRules)
}
req.reply(response)
}).as('getRules')
})
cy.fixture('documents/documents.json').then((documentsJson) => {
cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
})
})
})
cy.viewport(1024, 1600)
cy.visit('/settings')
})
it('should activate / deactivate save button when settings change and are saved', () => {
cy.contains('button', 'Save').should('be.disabled')
cy.contains('Use system settings').click()
cy.contains('button', 'Save').should('not.be.disabled')
cy.contains('button', 'Save').click()
cy.contains('button', 'Save').should('be.disabled')
})
it('should warn on unsaved changes', () => {
cy.contains('Use system settings').click()
cy.contains('a', 'Dashboard').click()
cy.contains('You have unsaved changes')
cy.contains('button', 'Cancel').click()
cy.contains('button', 'Save').click().wait(2000)
cy.contains('a', 'Dashboard').click()
cy.contains('You have unsaved changes').should('not.exist')
})
it('should apply appearance changes when set', () => {
cy.contains('Use system settings').click()
cy.get('body').should('not.have.class', 'color-scheme-system')
cy.contains('Enable dark mode').click()
cy.get('body').should('have.class', 'color-scheme-dark')
})
it('should remove saved view from sidebar when unset', () => {
cy.contains('a', 'Saved views').click().wait(2000)
cy.get('#show_in_sidebar_1').click()
cy.contains('button', 'Save').click().wait('@savedViews').wait(2000)
cy.contains('li', 'Inbox').should('not.exist')
})
it('should remove saved view from dashboard when unset', () => {
cy.contains('a', 'Saved views').click()
cy.get('#show_on_dashboard_1').click()
cy.contains('button', 'Save').click().wait('@savedViews').wait(2000)
cy.visit('/dashboard')
cy.get('app-saved-view-widget').contains('Inbox').should('not.exist')
})
it('should show a list of mail accounts & support creation', () => {
cy.contains('a', 'Mail').click()
cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
cy.contains('button', 'Add Account').click()
cy.contains('Create new mail account')
cy.get('app-input-text[formcontrolname="name"]').type(
'Example Mail Account'
)
cy.get('app-input-text[formcontrolname="imap_server"]').type(
'mail.example.com'
)
cy.get('app-input-text[formcontrolname="imap_port"]').type('993')
cy.get('app-input-text[formcontrolname="username"]').type('username')
cy.get('app-input-password[formcontrolname="password"]').type('pass')
cy.contains('app-mail-account-edit-dialog button', 'Save')
.click()
.wait('@saveAccount')
.wait('@getAccounts')
cy.contains('Saved account')
cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
})
it('should show a list of mail rules & support creation', () => {
cy.contains('a', 'Mail').click()
cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
cy.wait(1000)
cy.contains('button', 'Add Rule').click()
cy.contains('Create new mail rule')
cy.get('app-input-text[formcontrolname="name"]').type('Example Rule')
cy.get('app-input-select[formcontrolname="account"]').type('Example{enter}')
cy.get('app-input-number[formcontrolname="maximum_age"]').type('30')
cy.get('app-input-text[formcontrolname="filter_subject"]').type(
'[paperless]'
)
cy.contains('app-mail-rule-edit-dialog button', 'Save')
.click()
.wait('@saveRule')
.wait('@getRules')
cy.contains('Saved rule').wait(1000)
cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
})
})

View File

@ -1,93 +0,0 @@
describe('tasks', () => {
beforeEach(() => {
this.dismissedTasks = new Set<number>()
cy.fixture('tasks/tasks.json').then((tasksViewsJson) => {
// acknowledge tasks POST
cy.intercept(
'POST',
'http://localhost:8000/api/acknowledge_tasks/',
(req) => {
req.body['tasks'].forEach((t) => this.dismissedTasks.add(t)) // store this for later
req.reply({ result: 'OK' })
}
)
cy.intercept('GET', 'http://localhost:8000/api/tasks/', (req) => {
let response = [...tasksViewsJson]
if (this.dismissedTasks.size) {
response = response.filter((t) => {
return !this.dismissedTasks.has(t.id)
})
}
req.reply(response)
}).as('tasks')
})
cy.visit('/tasks')
cy.wait('@tasks')
})
it('should show a list of dismissable tasks in tabs', () => {
cy.get('tbody').find('tr:visible').its('length').should('eq', 10) // double because collapsible result tr
cy.wait(500) // stabilizes the test, for some reason...
cy.get('tbody')
.find('button:visible')
.contains('Dismiss')
.first()
.click()
.wait('@tasks')
.wait(2000)
.then(() => {
cy.get('tbody').find('tr:visible').its('length').should('eq', 8) // double because collapsible result tr
})
})
it('should correctly switch between task tabs', () => {
cy.get('tbody').find('tr:visible').its('length').should('eq', 10) // double because collapsible result tr
cy.wait(500) // stabilizes the test, for some reason...
cy.get('app-tasks')
.find('a:visible')
.contains('Queued')
.first()
.click()
.wait(2000)
.then(() => {
cy.get('tbody').find('tr:visible').should('not.exist')
})
cy.get('app-tasks')
.find('a:visible')
.contains('Started')
.first()
.click()
.wait(2000)
.then(() => {
cy.get('tbody').find('tr:visible').its('length').should('eq', 2) // double because collapsible result tr
})
cy.get('app-tasks')
.find('a:visible')
.contains('Complete')
.first()
.click()
.wait('@tasks')
.wait(2000)
.then(() => {
cy.get('tbody').find('tr:visible').its('length').should('eq', 12) // double because collapsible result tr
})
})
it('should allow toggling all tasks in list and warn on dismiss', () => {
cy.get('thead').find('input[type="checkbox"]').first().click()
cy.get('body').find('button').contains('Dismiss selected').first().click()
cy.contains('Confirm')
cy.get('.modal')
.contains('button', 'Dismiss')
.click()
.wait('@tasks')
.wait(2000)
.then(() => {
cy.get('tbody').find('tr:visible').should('not.exist')
})
})
})

View File

@ -1,257 +0,0 @@
{
"count": 27,
"next": "http://localhost:8000/api/correspondents/?page=2",
"previous": null,
"results": [
{
"id": 9,
"slug": "abc-test-correspondent",
"name": "ABC Test Correspondent",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 13,
"slug": "corresp-10",
"name": "Corresp 10",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 14,
"slug": "corresp-11",
"name": "Corresp 11",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 15,
"slug": "corresp-12",
"name": "Corresp 12",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 16,
"slug": "corresp-13",
"name": "Corresp 13",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 18,
"slug": "corresp-15",
"name": "Corresp 15",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 19,
"slug": "corresp-16",
"name": "Corresp 16",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 20,
"slug": "corresp-17",
"name": "Corresp 17",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 21,
"slug": "corresp-18",
"name": "Corresp 18",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 22,
"slug": "corresp-19",
"name": "Corresp 19",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 23,
"slug": "corresp-20",
"name": "Corresp 20",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 24,
"slug": "corresp-21",
"name": "Corresp 21",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 25,
"slug": "corresp-22",
"name": "Corresp 22",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 26,
"slug": "corresp-23",
"name": "Corresp 23",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 5,
"slug": "corresp-3",
"name": "Corresp 3",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 6,
"slug": "corresp-4",
"name": "Corresp 4",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 7,
"slug": "corresp-5",
"name": "Corresp 5",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 8,
"slug": "corresp-6",
"name": "Corresp 6",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 10,
"slug": "corresp-7",
"name": "Corresp 7",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 11,
"slug": "corresp-8",
"name": "Corresp 8",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 12,
"slug": "corresp-9",
"name": "Corresp 9",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 17,
"slug": "correspondent-14",
"name": "Correspondent 14",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 0,
"last_correspondence": null
},
{
"id": 2,
"slug": "correspondent-2",
"name": "Correspondent 2",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 7,
"last_correspondence": "2021-01-20T23:37:58.204614Z"
},
{
"id": 27,
"slug": "correspondent-slug",
"name": "Correspondent Slug",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 1,
"last_correspondence": "2022-03-16T03:48:50.089624Z"
},
{
"id": 4,
"slug": "newest-correspondent",
"name": "Newest Correspondent",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 1,
"last_correspondence": "2021-02-07T08:00:00Z"
}
]
}

View File

@ -1,25 +0,0 @@
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"slug": "test",
"name": "Test Doc Type",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 1
},
{
"id": 2,
"slug": "test2",
"name": "Test Doc Type 2",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"document_count": 1
}
]
}

View File

@ -1 +0,0 @@
{"original_checksum":"e959bc7d593245d92685213264e962ba","original_size":963754,"original_mime_type":"application/pdf","media_filename":"2022/lorem-ipsum.pdf","has_archive_version":true,"original_metadata":[],"archive_checksum":"5a1f46a9150bcade978c764b039ce4d0","archive_media_filename":"2022/lorem-ipsum.pdf","archive_size":351160,"archive_metadata":[{"namespace":"http://ns.adobe.com/pdf/1.3/","prefix":"pdf","key":"Producer","value":"pikepdf5.0.1"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"ModifyDate","value":"2022-03-22T04:53:18+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreateDate","value":"2022-03-22T18:05:43+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreatorTool","value":"ocrmypdf13.4.0/TesseractOCR-PDF4.1.1"},{"namespace":"http://ns.adobe.com/xap/1.0/mm/","prefix":"xmpMM","key":"DocumentID","value":"uuid:df27edcf-e34a-11f7-0000-8fa6067a3c04"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"format","value":"application/pdf"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"title","value":"ScannedDocument"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"part","value":"2"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"conformance","value":"B"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"creator","value":"None"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"MetadataDate","value":"2022-03-22T21:53:18.882551-07:00"}]}

View File

@ -1,26 +0,0 @@
[
{
"id": 10,
"note": "Testing new note",
"created": "2022-08-08T04:24:55.176008Z",
"user": 3
},
{
"id": 9,
"note": "Testing one more time",
"created": "2022-02-18T04:24:55.176008Z",
"user": 15
},
{
"id": 8,
"note": "Another note",
"created": "2021-11-08T04:24:47.925042Z",
"user": 3
},
{
"id": 7,
"note": "Cupcake ipsum dolor sit amet cheesecake candy cookie tiramisu. Donut chocolate chupa chups macaroon brownie halvah pie cheesecake gummies. Sweet chocolate bar candy donut gummi bears bear claw liquorice bonbon shortbread.\n\nDonut chocolate bar candy wafer wafer tiramisu. Gummies chocolate cake muffin toffee carrot cake macaroon. Toffee toffee jelly beans danish lollipop cake.",
"created": "2021-02-08T02:37:49.724132Z",
"user": 3
}
]

View File

@ -1 +0,0 @@
{"correspondents":[],"tags":[3],"document_types":[1]}

View File

@ -1,206 +0,0 @@
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"correspondent": 9,
"document_type": 1,
"storage_path": null,
"title": "No latin title",
"content": "Test document PDF \n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla est purus, ultrices in porttitor \nin, accumsan non quam. Nam consectetur porttitor rhoncus. Curabitur eu est et leo feugiat \nauctor vel quis lorem. Ut et ligula dolor, sit amet consequat lorem. Aliquam porta eros sed \nvelit imperdiet egestas. Maecenas tempus eros ut diam ullamcorper id dictum libero \ntempor. Donec quis augue quis magna condimentum lobortis. Quisque imperdiet ipsum vel \nmagna viverra rutrum. Cras viverra molestie urna, vitae vestibulum turpis varius id. \nVestibulum mollis, arcu iaculis bibendum varius, velit sapien blandit metus, ac posuere lorem \nnulla ac dolor. Maecenas urna elit, tincidunt in dapibus nec, vehicula eu dui. Duis lacinia \nfringilla massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur \nridiculus mus. Ut consequat ultricies est, non rhoncus mauris congue porta. Vivamus viverra \nsuscipit felis eget condimentum. Cum sociis natoque penatibus et magnis dis parturient \nmontes, nascetur ridiculus mus. Integer bibendum sagittis ligula, non faucibus nulla volutpat \nvitae. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. \nIn aliquet quam et velit bibendum accumsan. Cum sociis natoque penatibus et magnis dis \nparturient montes, nascetur ridiculus mus. Vestibulum vitae ipsum nec arcu semper \nadipiscing at ac lacus. Praesent id pellentesque orci. Morbi congue viverra nisl nec rhoncus. \nInteger mattis, ipsum a tincidunt commodo, lacus arcu elementum elit, at mollis eros ante ac \nrisus. In volutpat, ante at pretium ultricies, velit magna suscipit enim, aliquet blandit massa \norci nec lorem. Nulla facilisi. Duis eu vehicula arcu. Nulla facilisi. Maecenas pellentesque \nvolutpat felis, quis tristique ligula luctus vel. Sed nec mi eros. Integer augue enim, sollicitudin \nullamcorper mattis eget, aliquam in est. Morbi sollicitudin libero nec augue dignissim ut \nconsectetur dui volutpat. Nulla facilisi. Mauris egestas vestibulum neque cursus tincidunt. \nDonec sit amet pulvinar orci. \nQuisque volutpat pharetra tincidunt. Fusce sapien arcu, molestie eget varius egestas, \nfaucibus ac urna. Sed at nisi in velit egestas aliquam ut a felis. Aenean malesuada iaculis nisl, \nut tempor lacus egestas consequat. Nam nibh lectus, gravida sed egestas ut, feugiat quis \ndolor. Donec eu leo enim, non laoreet ante. Morbi dictum tempor vulputate. Phasellus \nultricies risus vel augue sagittis euismod. Vivamus tincidunt placerat nisi in aliquam. Cras \nquis mi ac nunc pretium aliquam. Aenean elementum erat ac metus commodo rhoncus. \nAliquam nulla augue, porta non sagittis quis, accumsan vitae sem. Phasellus id lectus tortor, \neget pulvinar augue. Etiam eget velit ac purus fringilla blandit. Donec odio odio, sagittis sed \niaculis sed, consectetur eget sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. \nMaecenas accumsan velit vel turpis rutrum in sodales diam placerat. \nQuisque luctus ullamcorper velit sit amet lobortis. Etiam ligula felis, vulputate quis rhoncus \nnec, fermentum eget odio. Vivamus vel ipsum ac augue sodales mollis euismod nec tellus. \nFusce et augue rutrum nunc semper vehicula vel semper nisl. Nam laoreet euismod quam at \nvarius. Sed aliquet auctor nibh. Curabitur malesuada fermentum lacus vel accumsan. Duis \nornare scelerisque nulla, ac pulvinar ligula tempus sit amet. In placerat nulla ac ante \nscelerisque posuere. Phasellus at ante felis. Sed hendrerit risus a metus posuere rutrum. \nPhasellus eu augue dui. Proin in vestibulum ipsum. Aenean accumsan mollis sapien, ut \neleifend sem blandit at. Vivamus luctus mi eget lorem lobortis pharetra. Phasellus at tortor \nquam, a volutpat purus. Etiam sollicitudin arcu vel elit bibendum et imperdiet risus tincidunt. \nEtiam elit velit, posuere ut pulvinar ac, condimentum eget justo. Fusce a erat velit. Vivamus \nimperdiet ultrices orci in hendrerit.",
"tags": [
4
],
"created": "2022-03-22T07:24:18Z",
"created_date": "2022-03-22",
"modified": "2022-03-22T07:24:23.264859Z",
"added": "2022-03-22T07:24:22.922631Z",
"archive_serial_number": null,
"original_file_name": "2022-03-22 no latin title.pdf",
"archived_file_name": "2022-03-22 no latin title.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": [
{
"id": 9,
"note": "Testing one more time",
"created": "2022-02-18T04:24:55.176008Z",
"user": 15
},
{
"id": 8,
"note": "Another note",
"created": "2021-11-08T04:24:47.925042Z",
"user": 3
},
{
"id": 7,
"note": "Cupcake ipsum dolor sit amet cheesecake candy cookie tiramisu. Donut chocolate chupa chups macaroon brownie halvah pie cheesecake gummies. Sweet chocolate bar candy donut gummi bears bear claw liquorice bonbon shortbread.\n\nDonut chocolate bar candy wafer wafer tiramisu. Gummies chocolate cake muffin toffee carrot cake macaroon. Toffee toffee jelly beans danish lollipop cake.",
"created": "2021-02-08T02:37:49.724132Z",
"user": 3
}
]
},
{
"id": 2,
"correspondent": null,
"document_type": null,
"storage_path": 2,
"title": "lorem ipsum dolor sit amet",
"content": "Test document PDF",
"tags": [],
"created": "2022-03-23T07:24:18Z",
"created_date": "2022-03-23",
"modified": "2022-03-23T07:24:23.264859Z",
"added": "2022-03-23T07:24:22.922631Z",
"archive_serial_number": 12345,
"original_file_name": "2022-03-23 lorem ipsum dolor sit amet.pdf",
"archived_file_name": "2022-03-23 llorem ipsum dolor sit amet.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": []
},
{
"id": 3,
"correspondent": 14,
"document_type": 1,
"storage_path": null,
"title": "dolor",
"content": "Test document PDF",
"tags": [
2
],
"created": "2022-03-24T07:24:18Z",
"created_date": "2022-03-24",
"modified": "2022-03-24T07:24:23.264859Z",
"added": "2022-03-24T07:24:22.922631Z",
"archive_serial_number": null,
"original_file_name": "2022-03-24 dolor.pdf",
"archived_file_name": "2022-03-24 dolor.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": []
},
{
"id": 4,
"correspondent": 9,
"document_type": 2,
"storage_path": null,
"title": "sit amet",
"content": "Test document PDF",
"tags": [
4, 5
],
"created": "2022-06-01T07:24:18Z",
"created_date": "2022-06-01",
"modified": "2022-06-01T07:24:23.264859Z",
"added": "2022-06-01T07:24:22.922631Z",
"archive_serial_number": 12347,
"original_file_name": "2022-06-01 sit amet.pdf",
"archived_file_name": "2022-06-01 sit amet.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": []
},
{
"id": 5,
"correspondent": null,
"document_type": null,
"storage_path": null,
"title": "Doc 5",
"content": "Test document 5",
"tags": [],
"created": "2023-05-01T07:24:18Z",
"created_date": "2023-05-02",
"modified": "2023-05-02T07:24:23.264859Z",
"added": "2023-05-02T07:24:22.922631Z",
"archive_serial_number": null,
"original_file_name": "doc5.pdf",
"archived_file_name": "doc5.pdf",
"owner": 15,
"user_can_change": true,
"permissions": {
"view": {
"users": [1],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": []
},
{
"id": 6,
"correspondent": null,
"document_type": null,
"storage_path": null,
"title": "Doc 6",
"content": "Test document 6",
"tags": [],
"created": "2023-05-01T10:24:18Z",
"created_date": "2023-05-02",
"modified": "2023-05-02T10:24:23.264859Z",
"added": "2023-05-02T10:24:22.922631Z",
"archive_serial_number": null,
"original_file_name": "doc6.pdf",
"archived_file_name": "doc6.pdf",
"owner": 6,
"user_can_change": true,
"permissions": {
"view": {
"users": [1],
"groups": []
},
"change": {
"users": [],
"groups": []
}
},
"notes": []
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

View File

@ -1,293 +0,0 @@
{
"selected_correspondents": [
{
"id": 62,
"document_count": 0
},
{
"id": 75,
"document_count": 0
},
{
"id": 55,
"document_count": 0
},
{
"id": 56,
"document_count": 0
},
{
"id": 73,
"document_count": 0
},
{
"id": 58,
"document_count": 0
},
{
"id": 44,
"document_count": 0
},
{
"id": 42,
"document_count": 0
},
{
"id": 74,
"document_count": 0
},
{
"id": 54,
"document_count": 0
},
{
"id": 29,
"document_count": 0
},
{
"id": 71,
"document_count": 0
},
{
"id": 68,
"document_count": 0
},
{
"id": 82,
"document_count": 0
},
{
"id": 34,
"document_count": 0
},
{
"id": 41,
"document_count": 0
},
{
"id": 51,
"document_count": 0
},
{
"id": 46,
"document_count": 0
},
{
"id": 40,
"document_count": 0
},
{
"id": 43,
"document_count": 0
},
{
"id": 80,
"document_count": 0
},
{
"id": 70,
"document_count": 0
},
{
"id": 52,
"document_count": 0
},
{
"id": 67,
"document_count": 0
},
{
"id": 53,
"document_count": 0
},
{
"id": 32,
"document_count": 0
},
{
"id": 63,
"document_count": 0
},
{
"id": 35,
"document_count": 0
},
{
"id": 45,
"document_count": 0
},
{
"id": 38,
"document_count": 0
},
{
"id": 79,
"document_count": 0
},
{
"id": 48,
"document_count": 0
},
{
"id": 72,
"document_count": 0
},
{
"id": 78,
"document_count": 0
},
{
"id": 39,
"document_count": 0
},
{
"id": 57,
"document_count": 0
},
{
"id": 61,
"document_count": 0
},
{
"id": 81,
"document_count": 0
},
{
"id": 77,
"document_count": 0
},
{
"id": 69,
"document_count": 0
},
{
"id": 36,
"document_count": 3
},
{
"id": 31,
"document_count": 0
},
{
"id": 30,
"document_count": 0
},
{
"id": 50,
"document_count": 0
},
{
"id": 49,
"document_count": 0
},
{
"id": 60,
"document_count": 0
},
{
"id": 47,
"document_count": 0
},
{
"id": 66,
"document_count": 0
},
{
"id": 37,
"document_count": 0
},
{
"id": 28,
"document_count": 0
},
{
"id": 59,
"document_count": 0
},
{
"id": 33,
"document_count": 0
},
{
"id": 76,
"document_count": 0
}
],
"selected_tags": [
{
"id": 4,
"document_count": 2
},
{
"id": 7,
"document_count": 0
},
{
"id": 5,
"document_count": 1
},
{
"id": 6,
"document_count": 0
},
{
"id": 3,
"document_count": 0
},
{
"id": 2,
"document_count": 1
},
{
"id": 1,
"document_count": 0
},
{
"id": 8,
"document_count": 0
}
],
"selected_document_types": [
{
"id": 4,
"document_count": 0
},
{
"id": 10,
"document_count": 0
},
{
"id": 2,
"document_count": 0
},
{
"id": 11,
"document_count": 0
},
{
"id": 9,
"document_count": 0
},
{
"id": 7,
"document_count": 2
},
{
"id": 3,
"document_count": 0
},
{
"id": 1,
"document_count": 0
},
{
"id": 5,
"document_count": 0
},
{
"id": 8,
"document_count": 1
}
],
"selected_storage_paths": []
}

View File

@ -1,119 +0,0 @@
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 6,
"name": "Another Group",
"permissions": [
"add_user",
"change_user",
"delete_user",
"view_user",
"add_note",
"change_note",
"delete_note",
"view_note"
]
},
{
"id": 1,
"name": "First Group",
"permissions": [
"add_group",
"change_group",
"delete_group",
"view_group",
"add_permission",
"change_permission",
"delete_permission",
"view_permission",
"add_token",
"change_token",
"delete_token",
"view_token",
"add_tokenproxy",
"change_tokenproxy",
"delete_tokenproxy",
"view_tokenproxy",
"add_contenttype",
"change_contenttype",
"delete_contenttype",
"view_contenttype",
"add_chordcounter",
"change_chordcounter",
"delete_chordcounter",
"view_chordcounter",
"add_groupresult",
"change_groupresult",
"delete_groupresult",
"view_groupresult",
"add_taskresult",
"change_taskresult",
"delete_taskresult",
"view_taskresult",
"add_failure",
"change_failure",
"delete_failure",
"view_failure",
"add_ormq",
"change_ormq",
"delete_ormq",
"view_ormq",
"add_schedule",
"change_schedule",
"delete_schedule",
"view_schedule",
"add_success",
"change_success",
"delete_success",
"view_success",
"add_task",
"change_task",
"delete_task",
"view_task",
"add_note",
"change_note",
"delete_note",
"view_note",
"add_correspondent",
"change_correspondent",
"delete_correspondent",
"view_correspondent",
"add_document",
"change_document",
"delete_document",
"view_document",
"add_documenttype",
"change_documenttype",
"delete_documenttype",
"view_documenttype",
"add_frontendsettings",
"change_frontendsettings",
"delete_frontendsettings",
"view_frontendsettings",
"add_log",
"change_log",
"delete_log",
"view_log",
"add_savedview",
"change_savedview",
"delete_savedview",
"view_savedview",
"add_savedviewfilterrule",
"change_savedviewfilterrule",
"delete_savedviewfilterrule",
"view_savedviewfilterrule",
"add_taskattributes",
"change_taskattributes",
"delete_taskattributes",
"view_taskattributes",
"add_session",
"change_session",
"delete_session",
"view_session"
]
}
]
}

View File

@ -1,27 +0,0 @@
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "IMAP Server",
"imap_server": "imap.example.com",
"imap_port": 993,
"imap_security": 2,
"username": "inbox@example.com",
"password": "pass",
"character_set": "UTF-8"
},
{
"id": 2,
"name": "Gmail",
"imap_server": "imap.gmail.com",
"imap_port": 993,
"imap_security": 2,
"username": "user@gmail.com",
"password": "pass",
"character_set": "UTF-8"
}
]
}

View File

@ -1,31 +0,0 @@
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Gmail",
"account": 2,
"folder": "INBOX",
"filter_from": null,
"filter_to": null,
"filter_subject": "[paperless]",
"filter_body": null,
"filter_attachment_filename": null,
"maximum_age": 30,
"action": 3,
"action_parameter": null,
"assign_title_from": 1,
"assign_tags": [
9
],
"assign_correspondent_from": 1,
"assign_correspondent": 2,
"assign_document_type": null,
"order": 0,
"attachment_type": 2,
"consumption_scope": 1
}
]
}

View File

@ -1 +0,0 @@
{"version":"v1.7.1","update_available":false,"feature_is_set":true}

View File

@ -1,44 +0,0 @@
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Inbox",
"show_on_dashboard": true,
"show_in_sidebar": true,
"sort_field": "created",
"sort_reverse": true,
"filter_rules": [
{
"rule_type": 6,
"value": "18"
}
]
},
{
"id": 2,
"name": "Recently Added",
"show_on_dashboard": true,
"show_in_sidebar": false,
"sort_field": "created",
"sort_reverse": true,
"filter_rules": []
},
{
"id": 11,
"name": "Taxes",
"show_on_dashboard": false,
"show_in_sidebar": true,
"sort_field": "created",
"sort_reverse": true,
"filter_rules": [
{
"rule_type": 6,
"value": "39"
}
]
}
]
}

View File

@ -1,17 +0,0 @@
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"slug": "year-title",
"name": "Year - Title",
"path": "{created_year}/{title}",
"match": "",
"matching_algorithm": 6,
"is_insensitive": true,
"document_count": 1
}
]
}

View File

@ -1,103 +0,0 @@
{
"count": 8,
"next": null,
"previous": null,
"results": [
{
"id": 4,
"slug": "another-sample-tag",
"name": "Another Sample Tag",
"color": "#a6cee3",
"text_color": "#000000",
"match": "",
"matching_algorithm": 6,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 3
},
{
"id": 7,
"slug": "newone",
"name": "NewOne",
"color": "#9e4ad1",
"text_color": "#ffffff",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 2
},
{
"id": 6,
"slug": "partial-tag",
"name": "Partial Tag",
"color": "#72dba7",
"text_color": "#000000",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 1
},
{
"id": 2,
"slug": "tag-2",
"name": "Tag 2",
"color": "#612db7",
"text_color": "#ffffff",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 3
},
{
"id": 3,
"slug": "tag-3",
"name": "Tag 3",
"color": "#b2df8a",
"text_color": "#000000",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 4
},
{
"id": 5,
"slug": "tagwithpartial",
"name": "TagWithPartial",
"color": "#3b2db4",
"text_color": "#ffffff",
"match": "",
"matching_algorithm": 6,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 2
},
{
"id": 8,
"slug": "test-another",
"name": "Test Another",
"color": "#3ccea5",
"text_color": "#000000",
"match": "",
"matching_algorithm": 4,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 0
},
{
"id": 1,
"slug": "test-tag",
"name": "Test Tag",
"color": "#fb9a99",
"text_color": "#000000",
"match": "",
"matching_algorithm": 1,
"is_insensitive": true,
"is_inbox_tag": false,
"document_count": 4
}
]
}

View File

@ -1,142 +0,0 @@
[
{
"id": 141,
"type": "file",
"result": "sample 2.pdf: Not consuming sample 2.pdf: It is a duplicate. : Traceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ngx.nosync-udqDZzaE/lib/python3.8/site-packages/django_q/cluster.py\", line 432, in worker\n res = f(*task[\"args\"], **task[\"kwargs\"])\n File \"/Users/admin/Documents/paperless-ngx/src/documents/tasks.py\", line 316, in consume_file\n document = Consumer().try_consume_file(\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 218, in try_consume_file\n self.pre_check_duplicate()\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 113, in pre_check_duplicate\n self._fail(\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 84, in _fail\n raise ConsumerError(f\"{self.filename}: {log_message or message}\")\ndocuments.consumer.ConsumerError: sample 2.pdf: Not consuming sample 2.pdf: It is a duplicate.\n",
"status": "FAILURE",
"task_id": "d8ddbe298a42427d82553206ddf0bc94",
"task_file_name": "sample 2.pdf",
"date_created": "2022-05-26T23:17:38.333474-07:00",
"date_done": null,
"acknowledged": false,
"related_document": null
},
{
"id": 132,
"type": "file",
"result": " : Traceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/subprocess.py\", line 131, in get_version\n env=env,\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/subprocess.py\", line 68, in run\n proc = subprocess_run(args, env=env, **kwargs)\n File \"/Users/admin/opt/anaconda3/envs/paperless-ng/lib/python3.6/subprocess.py\", line 423, in run\n with Popen(*popenargs, **kwargs) as process:\n File \"/Users/admin/opt/anaconda3/envs/paperless-ng/lib/python3.6/subprocess.py\", line 729, in __init__\n restore_signals, start_new_session)\n File \"/Users/admin/opt/anaconda3/envs/paperless-ng/lib/python3.6/subprocess.py\", line 1364, in _execute_child\n raise child_exception_type(errno_num, err_msg, err_filename)\nFileNotFoundError: [Errno 2] No such file or directory: 'unpaper': 'unpaper'\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/subprocess.py\", line 287, in check_external_program\n found_version = version_checker()\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/_exec/unpaper.py\", line 34, in version\n return get_version('unpaper')\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/subprocess.py\", line 137, in get_version\n ) from e\nocrmypdf.exceptions.MissingDependencyError: Could not find program 'unpaper' on the PATH\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/paperless_tesseract/parsers.py\", line 176, in parse\n ocrmypdf.ocr(**ocr_args)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/api.py\", line 315, in ocr\n check_options(options, plugin_manager)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/_validation.py\", line 260, in check_options\n _check_options(options, plugin_manager, ocr_engine_languages)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/_validation.py\", line 250, in _check_options\n check_options_preprocessing(options)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/_validation.py\", line 128, in check_options_preprocessing\n required_for=['--clean, --clean-final'],\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/ocrmypdf/subprocess.py\", line 293, in check_external_program\n raise MissingDependencyError()\nocrmypdf.exceptions.MissingDependencyError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 179, in try_consume_file\n document_parser.parse(self.path, mime_type, self.filename)\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/paperless_tesseract/parsers.py\", line 197, in parse\n raise ParseError(e)\ndocuments.parsers.ParseError\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/django_q/cluster.py\", line 436, in worker\n res = f(*task[\"args\"], **task[\"kwargs\"])\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/tasks.py\", line 73, in consume_file\n override_tag_ids=override_tag_ids)\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 196, in try_consume_file\n raise ConsumerError(e)\ndocuments.consumer.ConsumerError\n",
"status": "FAILURE",
"task_id": "4c554075552c4cc985abd76e6f274c90",
"task_file_name": "pdf-sample 10.24.48 PM.pdf",
"date_created": "2022-05-26T14:26:07.846365-07:00",
"date_done": null,
"acknowledged": null
},
{
"id": 115,
"type": "file",
"result": "2021-01-24 2021-01-20 sample_wide_orange.pdf: Document is a duplicate : Traceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/django_q/cluster.py\", line 436, in worker\n res = f(*task[\"args\"], **task[\"kwargs\"])\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/tasks.py\", line 75, in consume_file\n task_id=task_id\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 168, in try_consume_file\n self.pre_check_duplicate()\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 85, in pre_check_duplicate\n self._fail(\"Document is a duplicate\")\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 53, in _fail\n raise ConsumerError(f\"{self.filename}: {message}\")\ndocuments.consumer.ConsumerError: 2021-01-24 2021-01-20 sample_wide_orange.pdf: Document is a duplicate\n",
"status": "FAILURE",
"task_id": "86494713646a4364b01da17aadca071d",
"task_file_name": "2021-01-24 2021-01-20 sample_wide_orange.pdf",
"date_created": "2022-05-26T14:26:07.817608-07:00",
"date_done": null,
"acknowledged": null
},
{
"id": 85,
"type": "file",
"result": "cannot open resource : Traceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/django_q/cluster.py\", line 436, in worker\n res = f(*task[\"args\"], **task[\"kwargs\"])\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/tasks.py\", line 81, in consume_file\n task_id=task_id\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/consumer.py\", line 244, in try_consume_file\n self.path, mime_type, self.filename)\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/documents/parsers.py\", line 302, in get_optimised_thumbnail\n thumbnail = self.get_thumbnail(document_path, mime_type, file_name)\n File \"/Users/admin/Documents/Work/Contributions/paperless-ng/src/paperless_text/parsers.py\", line 29, in get_thumbnail\n layout_engine=ImageFont.LAYOUT_BASIC)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/PIL/ImageFont.py\", line 852, in truetype\n return freetype(font)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/PIL/ImageFont.py\", line 849, in freetype\n return FreeTypeFont(font, size, index, encoding, layout_engine)\n File \"/Users/admin/.local/share/virtualenvs/paperless-ng/lib/python3.6/site-packages/PIL/ImageFont.py\", line 210, in __init__\n font, size, index, encoding, layout_engine=layout_engine\nOSError: cannot open resource\n",
"status": "FAILURE",
"task_id": "abca803fa46342e1ac81f3d3f2080e79",
"task_file_name": "simple.txt",
"date_created": "2022-05-26T14:26:07.771541-07:00",
"date_done": null,
"acknowledged": null
},
{
"id": 41,
"type": "file",
"result": "commands.txt: Not consuming commands.txt: It is a duplicate. : Traceback (most recent call last):\n File \"/Users/admin/.local/share/virtualenvs/paperless-ngx.nosync-udqDZzaE/lib/python3.8/site-packages/django_q/cluster.py\", line 432, in worker\n res = f(*task[\"args\"], **task[\"kwargs\"])\n File \"/Users/admin/Documents/paperless-ngx/src/documents/tasks.py\", line 70, in consume_file\n document = Consumer().try_consume_file(\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 199, in try_consume_file\n self.pre_check_duplicate()\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 97, in pre_check_duplicate\n self._fail(\n File \"/Users/admin/Documents/paperless-ngx/src/documents/consumer.py\", line 69, in _fail\n raise ConsumerError(f\"{self.filename}: {log_message or message}\")\ndocuments.consumer.ConsumerError: commands.txt: Not consuming commands.txt: It is a duplicate.\n",
"status": "FAILURE",
"task_id": "0af67672e8e14404b060d4cf8f69313d",
"task_file_name": "commands.txt",
"date_created": "2022-05-26T14:26:07.704247-07:00",
"date_done": null,
"acknowledged": null
},
{
"id": 10,
"type": "file",
"result": "Success. New document id 260 created",
"status": "SUCCESS",
"task_id": "b7629a0f41bd40c7a3ea4680341321b5",
"task_file_name": "2022-03-24+Sonstige+ScanPC2022-03-24_081058.pdf",
"date_created": "2022-05-26T14:26:07.670577-07:00",
"date_done": "2022-05-26T14:26:07.670577-07:00",
"acknowledged": false,
"related_document": 260
},
{
"id": 9,
"type": "file",
"result": "Success. New document id 261 created",
"status": "SUCCESS",
"task_id": "02e276a86a424ccfb83309df5d8594be",
"task_file_name": "2sample-pdf-with-images.pdf",
"date_created": "2022-05-26T14:26:07.668987-07:00",
"date_done": "2022-05-26T14:26:07.668987-07:00",
"acknowledged": false,
"related_document": 261
},
{
"id": 8,
"type": "file",
"result": "Success. New document id 262 created",
"status": "SUCCESS",
"task_id": "41229b8be9b445c0a523697d0f58f13e",
"task_file_name": "2sample-pdf-with-images_pw.pdf",
"date_created": "2022-05-26T14:26:07.667993-07:00",
"date_done": "2022-05-26T14:26:07.667993-07:00",
"acknowledged": false,
"related_document": 262
},
{
"id": 6,
"type": "file",
"result": "Success. New document id 264 created",
"status": "SUCCESS",
"task_id": "bbbca32d408c4619bd0b512a8327c773",
"task_file_name": "homebridge.log",
"date_created": "2022-05-26T14:26:07.665560-07:00",
"date_done": "2022-05-26T14:26:07.665560-07:00",
"acknowledged": false,
"related_document": 264
},
{
"id": 5,
"type": "file",
"result": "Success. New document id 265 created",
"status": "SUCCESS",
"task_id": "00ab285ab4bf482ab30c7d580b252ecb",
"task_file_name": "IMG_7459.PNG",
"date_created": "2022-05-26T14:26:07.664506-07:00",
"date_done": "2022-05-26T14:26:07.664506-07:00",
"acknowledged": false,
"related_document": 265
},
{
"id": 3,
"type": "file",
"result": "Success. New document id 267 created",
"status": "SUCCESS",
"task_id": "289c5163cfec410db42948a0cacbeb9c",
"task_file_name": "IMG_7459.PNG",
"date_created": "2022-05-26T14:26:07.659661-07:00",
"date_done": "2022-05-26T14:26:07.659661-07:00",
"acknowledged": false,
"related_document": 267
},
{
"id": 1,
"type": "file",
"result": null,
"status": "STARTED",
"task_id": "7a4ebdb2bde04311935284027ef8ca65",
"task_file_name": "2019-08-04 DSA Questionnaire - 5-8-19.pdf",
"date_created": "2022-05-26T14:26:07.655276-07:00",
"date_done": null,
"acknowledged": false,
"related_document": null
}
]

View File

@ -1,163 +0,0 @@
{
"user": {
"id": 1,
"username": "admin",
"is_superuser": true,
"groups": []
},
"settings": {
"language": "",
"bulk_edit": {
"confirmation_dialogs": true,
"apply_on_close": false
},
"documentListSize": 50,
"dark_mode": {
"use_system": true,
"enabled": "false",
"thumb_inverted": "true"
},
"theme": {
"color": "#b198e5"
},
"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
}
},
"permissions": [
"add_logentry",
"change_logentry",
"delete_logentry",
"view_logentry",
"add_group",
"change_group",
"delete_group",
"view_group",
"add_permission",
"change_permission",
"delete_permission",
"view_permission",
"add_user",
"change_user",
"delete_user",
"view_user",
"add_token",
"change_token",
"delete_token",
"view_token",
"add_tokenproxy",
"change_tokenproxy",
"delete_tokenproxy",
"view_tokenproxy",
"add_contenttype",
"change_contenttype",
"delete_contenttype",
"view_contenttype",
"add_chordcounter",
"change_chordcounter",
"delete_chordcounter",
"view_chordcounter",
"add_groupresult",
"change_groupresult",
"delete_groupresult",
"view_groupresult",
"add_taskresult",
"change_taskresult",
"delete_taskresult",
"view_taskresult",
"add_failure",
"change_failure",
"delete_failure",
"view_failure",
"add_ormq",
"change_ormq",
"delete_ormq",
"view_ormq",
"add_schedule",
"change_schedule",
"delete_schedule",
"view_schedule",
"add_success",
"change_success",
"delete_success",
"view_success",
"add_task",
"change_task",
"delete_task",
"view_task",
"add_note",
"change_note",
"delete_note",
"view_note",
"add_correspondent",
"change_correspondent",
"delete_correspondent",
"view_correspondent",
"add_document",
"change_document",
"delete_document",
"view_document",
"add_documenttype",
"change_documenttype",
"delete_documenttype",
"view_documenttype",
"add_frontendsettings",
"change_frontendsettings",
"delete_frontendsettings",
"view_frontendsettings",
"add_log",
"change_log",
"delete_log",
"view_log",
"add_paperlesstask",
"change_paperlesstask",
"delete_paperlesstask",
"view_paperlesstask",
"add_savedview",
"change_savedview",
"delete_savedview",
"view_savedview",
"add_savedviewfilterrule",
"change_savedviewfilterrule",
"delete_savedviewfilterrule",
"view_savedviewfilterrule",
"add_storagepath",
"change_storagepath",
"delete_storagepath",
"view_storagepath",
"add_tag",
"change_tag",
"delete_tag",
"view_tag",
"add_taskattributes",
"change_taskattributes",
"delete_taskattributes",
"view_taskattributes",
"add_uisettings",
"change_uisettings",
"delete_uisettings",
"view_uisettings",
"add_mailaccount",
"change_mailaccount",
"delete_mailaccount",
"view_mailaccount",
"add_mailrule",
"change_mailrule",
"delete_mailrule",
"view_mailrule",
"add_session",
"change_session",
"delete_session",
"view_session"
]
}

View File

@ -1,88 +0,0 @@
{
"user": {
"id": 1,
"username": "admin",
"is_superuser": false,
"groups": []
},
"settings": {
"language": "",
"bulk_edit": {
"confirmation_dialogs": true,
"apply_on_close": false
},
"documentListSize": 50,
"dark_mode": {
"use_system": true,
"enabled": "false",
"thumb_inverted": "true"
},
"theme": {
"color": "#b198e5"
},
"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
}
},
"permissions": [
"add_token",
"change_token",
"delete_token",
"view_token",
"add_tokenproxy",
"change_tokenproxy",
"delete_tokenproxy",
"view_tokenproxy",
"add_contenttype",
"change_contenttype",
"delete_contenttype",
"view_contenttype",
"add_chordcounter",
"change_chordcounter",
"delete_chordcounter",
"view_chordcounter",
"add_groupresult",
"change_groupresult",
"delete_groupresult",
"view_groupresult",
"add_failure",
"change_failure",
"delete_failure",
"view_failure",
"add_ormq",
"change_ormq",
"delete_ormq",
"view_ormq",
"add_schedule",
"change_schedule",
"delete_schedule",
"view_schedule",
"add_success",
"change_success",
"delete_success",
"view_success",
"add_task",
"change_task",
"delete_task",
"view_task",
"add_note",
"add_frontendsettings",
"change_frontendsettings",
"delete_frontendsettings",
"view_frontendsettings",
"add_session",
"change_session",
"delete_session",
"view_session"
]
}

View File

@ -1,459 +0,0 @@
{
"count": 4,
"next": null,
"previous": null,
"results": [
{
"id": 3,
"username": "admin",
"password": "**********",
"first_name": "",
"last_name": "",
"date_joined": "2022-02-14T23:11:09.103293Z",
"is_staff": true,
"is_active": true,
"is_superuser": true,
"groups": [],
"user_permissions": [],
"inherited_permissions": [
"auth.delete_permission",
"paperless_mail.change_mailrule",
"django_celery_results.add_taskresult",
"documents.view_taskattributes",
"documents.view_paperlesstask",
"django_q.add_success",
"documents.view_uisettings",
"auth.change_user",
"admin.delete_logentry",
"django_celery_results.change_taskresult",
"django_q.change_schedule",
"django_celery_results.delete_taskresult",
"paperless_mail.add_mailaccount",
"auth.change_group",
"documents.add_note",
"paperless_mail.delete_mailaccount",
"authtoken.delete_tokenproxy",
"guardian.delete_groupobjectpermission",
"contenttypes.delete_contenttype",
"documents.change_correspondent",
"authtoken.delete_token",
"documents.delete_documenttype",
"django_q.change_ormq",
"documents.change_savedviewfilterrule",
"auth.delete_group",
"documents.add_documenttype",
"django_q.change_success",
"documents.delete_tag",
"documents.change_note",
"django_q.delete_task",
"documents.add_savedviewfilterrule",
"django_q.view_task",
"paperless_mail.add_mailrule",
"paperless_mail.view_mailaccount",
"documents.add_frontendsettings",
"sessions.change_session",
"documents.view_savedview",
"authtoken.add_tokenproxy",
"documents.change_tag",
"documents.view_document",
"documents.add_savedview",
"auth.delete_user",
"documents.view_log",
"documents.view_note",
"guardian.change_groupobjectpermission",
"sessions.delete_session",
"django_q.change_failure",
"guardian.change_userobjectpermission",
"documents.change_storagepath",
"documents.delete_document",
"documents.delete_taskattributes",
"django_celery_results.change_groupresult",
"django_q.add_ormq",
"guardian.view_groupobjectpermission",
"admin.change_logentry",
"django_q.delete_schedule",
"documents.delete_paperlesstask",
"django_q.view_ormq",
"documents.change_paperlesstask",
"guardian.delete_userobjectpermission",
"auth.view_permission",
"auth.view_user",
"django_q.add_schedule",
"authtoken.change_token",
"guardian.add_groupobjectpermission",
"documents.view_documenttype",
"documents.change_log",
"paperless_mail.delete_mailrule",
"auth.view_group",
"authtoken.view_token",
"admin.view_logentry",
"django_celery_results.view_chordcounter",
"django_celery_results.view_groupresult",
"documents.view_storagepath",
"documents.add_storagepath",
"django_celery_results.add_groupresult",
"documents.view_tag",
"guardian.view_userobjectpermission",
"documents.delete_correspondent",
"documents.add_tag",
"documents.delete_savedviewfilterrule",
"documents.add_correspondent",
"authtoken.view_tokenproxy",
"documents.delete_frontendsettings",
"django_celery_results.delete_chordcounter",
"django_q.change_task",
"documents.add_taskattributes",
"documents.delete_storagepath",
"sessions.add_session",
"documents.add_uisettings",
"documents.change_taskattributes",
"documents.delete_uisettings",
"django_q.delete_ormq",
"auth.change_permission",
"documents.view_savedviewfilterrule",
"documents.change_frontendsettings",
"documents.change_documenttype",
"documents.view_correspondent",
"auth.add_user",
"paperless_mail.change_mailaccount",
"documents.add_paperlesstask",
"django_q.view_success",
"django_celery_results.delete_groupresult",
"documents.delete_savedview",
"authtoken.change_tokenproxy",
"documents.view_frontendsettings",
"authtoken.add_token",
"django_celery_results.add_chordcounter",
"contenttypes.change_contenttype",
"admin.add_logentry",
"django_q.delete_failure",
"documents.change_uisettings",
"django_q.view_failure",
"documents.add_log",
"documents.change_savedview",
"paperless_mail.view_mailrule",
"django_q.view_schedule",
"documents.change_document",
"django_celery_results.change_chordcounter",
"documents.add_document",
"django_celery_results.view_taskresult",
"contenttypes.add_contenttype",
"django_q.delete_success",
"documents.delete_note",
"django_q.add_failure",
"guardian.add_userobjectpermission",
"sessions.view_session",
"contenttypes.view_contenttype",
"auth.add_permission",
"documents.delete_log",
"django_q.add_task",
"auth.add_group"
]
},
{
"id": 15,
"username": "test",
"password": "**********",
"first_name": "",
"last_name": "",
"date_joined": "2022-11-23T08:30:54Z",
"is_staff": true,
"is_active": true,
"is_superuser": false,
"groups": [
1
],
"user_permissions": [
"add_group",
"change_group",
"delete_group",
"view_group",
"add_permission",
"change_permission",
"delete_permission",
"view_permission",
"add_token",
"change_token",
"delete_token",
"view_token",
"add_tokenproxy",
"change_tokenproxy",
"delete_tokenproxy",
"view_tokenproxy",
"add_contenttype",
"change_contenttype",
"delete_contenttype",
"view_contenttype",
"add_chordcounter",
"change_chordcounter",
"delete_chordcounter",
"view_chordcounter",
"add_groupresult",
"change_groupresult",
"delete_groupresult",
"view_groupresult",
"add_taskresult",
"change_taskresult",
"delete_taskresult",
"view_taskresult",
"add_failure",
"change_failure",
"delete_failure",
"view_failure",
"add_ormq",
"change_ormq",
"delete_ormq",
"view_ormq",
"add_schedule",
"change_schedule",
"delete_schedule",
"view_schedule",
"add_success",
"change_success",
"delete_success",
"view_success",
"add_task",
"change_task",
"delete_task",
"view_task",
"add_note",
"change_note",
"delete_note",
"view_note",
"add_frontendsettings",
"change_frontendsettings",
"delete_frontendsettings",
"view_frontendsettings",
"add_log",
"change_log",
"delete_log",
"view_log",
"add_savedviewfilterrule",
"change_savedviewfilterrule",
"delete_savedviewfilterrule",
"view_savedviewfilterrule",
"add_taskattributes",
"change_taskattributes",
"delete_taskattributes",
"view_taskattributes",
"add_session",
"change_session",
"delete_session",
"view_session"
],
"inherited_permissions": [
"auth.delete_permission",
"django_celery_results.add_taskresult",
"documents.view_taskattributes",
"django_q.add_ormq",
"django_q.add_success",
"django_q.delete_schedule",
"django_q.view_ormq",
"auth.view_permission",
"django_q.add_schedule",
"django_celery_results.change_taskresult",
"django_q.change_schedule",
"django_celery_results.delete_taskresult",
"authtoken.change_token",
"auth.change_group",
"documents.add_note",
"authtoken.delete_tokenproxy",
"documents.view_documenttype",
"contenttypes.delete_contenttype",
"documents.change_correspondent",
"authtoken.delete_token",
"documents.change_log",
"auth.view_group",
"authtoken.view_token",
"django_celery_results.view_chordcounter",
"django_celery_results.view_groupresult",
"documents.delete_documenttype",
"django_q.change_ormq",
"documents.change_savedviewfilterrule",
"django_celery_results.add_groupresult",
"auth.delete_group",
"documents.add_documenttype",
"django_q.change_success",
"auth.add_permission",
"documents.delete_correspondent",
"documents.delete_savedviewfilterrule",
"documents.add_correspondent",
"authtoken.view_tokenproxy",
"documents.delete_frontendsettings",
"django_celery_results.delete_chordcounter",
"documents.add_taskattributes",
"django_q.change_task",
"sessions.add_session",
"documents.change_taskattributes",
"documents.change_note",
"django_q.delete_task",
"django_q.delete_ormq",
"auth.change_permission",
"documents.add_savedviewfilterrule",
"django_q.view_task",
"documents.view_savedviewfilterrule",
"documents.change_frontendsettings",
"documents.change_documenttype",
"documents.view_correspondent",
"django_q.view_success",
"documents.add_frontendsettings",
"django_celery_results.delete_groupresult",
"documents.delete_savedview",
"authtoken.change_tokenproxy",
"documents.view_frontendsettings",
"authtoken.add_token",
"sessions.change_session",
"django_celery_results.add_chordcounter",
"documents.view_savedview",
"contenttypes.change_contenttype",
"django_q.delete_failure",
"authtoken.add_tokenproxy",
"documents.view_document",
"documents.add_savedview",
"django_q.view_failure",
"documents.view_note",
"documents.view_log",
"documents.add_log",
"documents.change_savedview",
"django_q.view_schedule",
"documents.change_document",
"django_celery_results.change_chordcounter",
"documents.add_document",
"sessions.delete_session",
"django_q.change_failure",
"django_celery_results.view_taskresult",
"contenttypes.add_contenttype",
"django_q.delete_success",
"documents.delete_note",
"django_q.add_failure",
"sessions.view_session",
"contenttypes.view_contenttype",
"documents.delete_taskattributes",
"documents.delete_document",
"documents.delete_log",
"django_q.add_task",
"django_celery_results.change_groupresult",
"auth.add_group"
]
},
{
"id": 6,
"username": "testuser",
"password": "**********",
"first_name": "",
"last_name": "",
"date_joined": "2022-11-16T04:14:20.484914Z",
"is_staff": false,
"is_active": true,
"is_superuser": false,
"groups": [
1,
6
],
"user_permissions": [
"add_logentry",
"change_logentry",
"delete_logentry",
"view_logentry"
],
"inherited_permissions": [
"auth.delete_permission",
"django_celery_results.add_taskresult",
"documents.view_taskattributes",
"django_q.add_ormq",
"django_q.add_success",
"django_q.delete_schedule",
"django_q.view_ormq",
"auth.change_user",
"auth.view_permission",
"auth.view_user",
"django_q.add_schedule",
"django_celery_results.change_taskresult",
"django_q.change_schedule",
"django_celery_results.delete_taskresult",
"authtoken.change_token",
"auth.change_group",
"documents.add_note",
"authtoken.delete_tokenproxy",
"documents.view_documenttype",
"contenttypes.delete_contenttype",
"documents.change_correspondent",
"authtoken.delete_token",
"documents.change_log",
"auth.view_group",
"authtoken.view_token",
"django_celery_results.view_chordcounter",
"django_celery_results.view_groupresult",
"documents.delete_documenttype",
"django_q.change_ormq",
"documents.change_savedviewfilterrule",
"django_celery_results.add_groupresult",
"auth.delete_group",
"documents.add_documenttype",
"django_q.change_success",
"auth.add_permission",
"documents.delete_correspondent",
"documents.delete_savedviewfilterrule",
"documents.add_correspondent",
"authtoken.view_tokenproxy",
"documents.delete_frontendsettings",
"django_celery_results.delete_chordcounter",
"documents.add_taskattributes",
"django_q.change_task",
"sessions.add_session",
"documents.change_taskattributes",
"documents.change_note",
"django_q.delete_task",
"django_q.delete_ormq",
"auth.change_permission",
"documents.add_savedviewfilterrule",
"django_q.view_task",
"documents.view_savedviewfilterrule",
"documents.change_frontendsettings",
"documents.change_documenttype",
"documents.view_correspondent",
"auth.add_user",
"django_q.view_success",
"documents.add_frontendsettings",
"django_celery_results.delete_groupresult",
"documents.delete_savedview",
"authtoken.change_tokenproxy",
"documents.view_frontendsettings",
"authtoken.add_token",
"sessions.change_session",
"django_celery_results.add_chordcounter",
"documents.view_savedview",
"contenttypes.change_contenttype",
"django_q.delete_failure",
"authtoken.add_tokenproxy",
"documents.view_document",
"documents.add_savedview",
"django_q.view_failure",
"documents.view_note",
"documents.view_log",
"auth.delete_user",
"documents.add_log",
"documents.change_savedview",
"django_q.view_schedule",
"documents.change_document",
"django_celery_results.change_chordcounter",
"documents.add_document",
"sessions.delete_session",
"django_q.change_failure",
"django_celery_results.view_taskresult",
"contenttypes.add_contenttype",
"django_q.delete_success",
"documents.delete_note",
"django_q.add_failure",
"sessions.view_session",
"contenttypes.view_contenttype",
"documents.delete_taskattributes",
"documents.delete_document",
"documents.delete_log",
"django_q.add_task",
"django_celery_results.change_groupresult",
"auth.add_group"
]
}
]
}

View File

@ -1,3 +0,0 @@
// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress
// For more info, visit https://on.cypress.io/plugins-api
module.exports = (on, config) => {}

View File

@ -1,43 +0,0 @@
// ***********************************************
// This example namespace declaration will help
// with Intellisense and code completion in your
// IDE or Text Editor.
// ***********************************************
// declare namespace Cypress {
// interface Chainable<Subject = any> {
// customCommand(param: any): typeof customCommand;
// }
// }
//
// function customCommand(param: any): void {
// console.warn(param);
// }
//
// NOTE: You can use it like so:
// Cypress.Commands.add('customCommand', customCommand);
//
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

View File

@ -1,55 +0,0 @@
// mock API methods
beforeEach(() => {
cy.intercept('http://localhost:8000/api/ui_settings/', {
fixture: 'ui_settings/settings.json',
}).as('ui-settings')
cy.intercept('http://localhost:8000/api/users/*', {
fixture: 'users/users.json',
})
cy.intercept('http://localhost:8000/api/groups/*', {
fixture: 'groups/groups.json',
})
cy.intercept('http://localhost:8000/api/remote_version/', {
fixture: 'remote_version/remote_version.json',
})
cy.intercept('http://localhost:8000/api/saved_views/*', {
fixture: 'saved_views/savedviews.json',
})
cy.intercept('http://localhost:8000/api/tags/*', {
fixture: 'tags/tags.json',
})
cy.intercept('http://localhost:8000/api/correspondents/*', {
fixture: 'correspondents/correspondents.json',
})
cy.intercept('http://localhost:8000/api/document_types/*', {
fixture: 'document_types/doctypes.json',
})
cy.intercept('http://localhost:8000/api/storage_paths/*', {
fixture: 'storage_paths/storage_paths.json',
})
cy.intercept('http://localhost:8000/api/tasks/', {
fixture: 'tasks/tasks.json',
})
cy.intercept('http://localhost:8000/api/documents/1/metadata/', {
fixture: 'documents/1/metadata.json',
})
cy.intercept('http://localhost:8000/api/documents/1/suggestions/', {
fixture: 'documents/1/suggestions.json',
})
cy.intercept('http://localhost:8000/api/documents/1/thumb/', {
fixture: 'documents/lorem-ipsum.png',
})
})

View File

@ -1,8 +0,0 @@
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"sourceMap": false,
"types": ["cypress"]
}
}

View 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()
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
})

File diff suppressed because one or more lines are too long

View 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
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
)
})

View 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 }
}
]
}
}

View File

@ -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,
},
})
)
},
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
})

View File

@ -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)
)
})
})

View File

@ -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>
}
}

File diff suppressed because one or more lines are too long

View 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)
})

View File

@ -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"
]
}
}

1721
src-ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,7 @@
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"cy:run": "cypress run",
"e2e:ci": "concurrently 'npm run start' 'wait-on http-get://localhost:4200 && npm run cy:run' --kill-others --success first"
"lint": "ng lint"
},
"private": true,
"dependencies": {
@ -48,6 +45,7 @@
"@angular-eslint/template-parser": "15.2.1",
"@angular/cli": "~15.2.7",
"@angular/compiler-cli": "~15.2.8",
"@playwright/test": "^1.33.0",
"@types/jest": "^29.5.0",
"@types/node": "^18.16.3",
"@typescript-eslint/eslint-plugin": "^5.59.2",
@ -60,9 +58,5 @@
"ts-node": "~10.9.1",
"typescript": "~4.9.5",
"wait-on": "^7.0.1"
},
"optionalDependencies": {
"@cypress/schematic": "^2.1.1",
"cypress": "^12.11.0"
}
}

View File

@ -0,0 +1,74 @@
import { defineConfig, devices } from '@playwright/test'
const port = 4200
const baseURL = `http://localhost:${port}`
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 3 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Run your local dev server before starting the tests */
webServer: {
port,
command: 'npm run start',
reuseExistingServer: !process.env.CI,
timeout: 2 * 60 * 1000,
},
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
// },
],
})

View File

@ -60,7 +60,8 @@ export class SavedViewWidgetComponent
10,
this.savedView.sort_field,
this.savedView.sort_reverse,
this.savedView.filter_rules
this.savedView.filter_rules,
{ truncate_content: true }
)
.subscribe((result) => {
this.loading = false