Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions playwright/e2e/collective-print.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { expect } from '@playwright/test'
import { test } from '../support/fixtures/create-collectives.ts'

test.describe('Collective print view', () => {
test('loads all images before opening print dialog', async ({ user, page, collective }) => {
// Create two pages each with an image. The second page is below initial viewport.
for (let i = 0; i < 2; i++) {
const collectivePage = await collective.createPage({
title: `Page with image ${i}`,
user,
page,
})
const src = await collectivePage.uploadImage({
filename: 'test.png',
user,
page,
})
await collectivePage.setContent({
content: `# Image ${i}\n\n![image ${i}](${src})\n`,
user,
page,
})
}

// Stub window.print so the real print dialog doesn't block the test
await page.addInitScript(() => {
(window as Window & { __printCalls?: number }).__printCalls = 0
window.print = () => {
(window as Window & { __printCalls?: number }).__printCalls! += 1
}
})

await page.goto(`/index.php/apps/collectives/_/print/${collective.getCollectiveUrlPart()}`)

await expect(page.getByText('Preparing collective for exporting or printing'))
.toBeVisible()
await expect(page.getByText('Preparing collective for exporting or printing'))
.toBeHidden({ timeout: 30000 })

const printCalls = await page.evaluate(() => (window as Window & { __printCalls?: number }).__printCalls)
expect(printCalls).toBeGreaterThan(0)

const imgs = page.locator('div.ProseMirror figure.image img.image__main')
const count = await imgs.count()
expect(count).toBe(2)

Check failure on line 50 in playwright/e2e/collective-print.spec.ts

View workflow job for this annotation

GitHub Actions / playwright (stable32, 1, 4)

[chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog

1) [chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: 2 Received: 1 48 | const imgs = page.locator('div.ProseMirror figure.image img.image__main') 49 | const count = await imgs.count() > 50 | expect(count).toBe(2) | ^ 51 | for (let i = 0; i < count; i++) { 52 | const naturalWidth = await imgs.nth(i).evaluate((el: HTMLImageElement) => el.naturalWidth) 53 | expect(naturalWidth, `image ${i} should have loaded`).toBeGreaterThan(0) at /home/runner/work/collectives/collectives/playwright/e2e/collective-print.spec.ts:50:17

Check failure on line 50 in playwright/e2e/collective-print.spec.ts

View workflow job for this annotation

GitHub Actions / playwright (stable32, 1, 4)

[chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog

1) [chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog Error: expect(received).toBe(expected) // Object.is equality Expected: 2 Received: 1 48 | const imgs = page.locator('div.ProseMirror figure.image img.image__main') 49 | const count = await imgs.count() > 50 | expect(count).toBe(2) | ^ 51 | for (let i = 0; i < count; i++) { 52 | const naturalWidth = await imgs.nth(i).evaluate((el: HTMLImageElement) => el.naturalWidth) 53 | expect(naturalWidth, `image ${i} should have loaded`).toBeGreaterThan(0) at /home/runner/work/collectives/collectives/playwright/e2e/collective-print.spec.ts:50:17

Check failure on line 50 in playwright/e2e/collective-print.spec.ts

View workflow job for this annotation

GitHub Actions / playwright (master, 1, 4)

[chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog

1) [chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: 2 Received: 1 48 | const imgs = page.locator('div.ProseMirror figure.image img.image__main') 49 | const count = await imgs.count() > 50 | expect(count).toBe(2) | ^ 51 | for (let i = 0; i < count; i++) { 52 | const naturalWidth = await imgs.nth(i).evaluate((el: HTMLImageElement) => el.naturalWidth) 53 | expect(naturalWidth, `image ${i} should have loaded`).toBeGreaterThan(0) at /home/runner/work/collectives/collectives/playwright/e2e/collective-print.spec.ts:50:17

Check failure on line 50 in playwright/e2e/collective-print.spec.ts

View workflow job for this annotation

GitHub Actions / playwright (master, 1, 4)

[chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog

1) [chromium] › playwright/e2e/collective-print.spec.ts:10:2 › Collective print view › loads all images before opening print dialog Error: expect(received).toBe(expected) // Object.is equality Expected: 2 Received: 1 48 | const imgs = page.locator('div.ProseMirror figure.image img.image__main') 49 | const count = await imgs.count() > 50 | expect(count).toBe(2) | ^ 51 | for (let i = 0; i < count; i++) { 52 | const naturalWidth = await imgs.nth(i).evaluate((el: HTMLImageElement) => el.naturalWidth) 53 | expect(naturalWidth, `image ${i} should have loaded`).toBeGreaterThan(0) at /home/runner/work/collectives/collectives/playwright/e2e/collective-print.spec.ts:50:17
for (let i = 0; i < count; i++) {
const naturalWidth = await imgs.nth(i).evaluate((el: HTMLImageElement) => el.naturalWidth)
expect(naturalWidth, `image ${i} should have loaded`).toBeGreaterThan(0)
}
})
})
41 changes: 41 additions & 0 deletions playwright/support/fixtures/CollectivePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import type { Page } from '@playwright/test'
import type { User } from './User.ts'

import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { webdavUrl } from '../helpers/urls.ts'

type CollectivePageData = {
Expand Down Expand Up @@ -156,4 +158,43 @@ export class CollectivePage {
const content = `## Link\n\n[${linkText}](${linkUrl})`
await this.setContent({ content, user, page })
}

async uploadImage({ filename, mimetype = 'image/png', user, page }: {
filename: string
mimetype?: string
user: User
page: Page
}): Promise<string> {
const attachmentsDir = `.attachments.${this.data.id}`

// MKCOL is idempotent enough: 201 = created, 405 = already exists
const dirUrl = webdavUrl(
user.account.userId,
this.data.collectivePath,
this.data.filePath,
attachmentsDir,
)
const mkcol = await page.request.fetch(dirUrl, { method: 'MKCOL' })
if (![201, 405].includes(mkcol.status())) {
throw new Error(`MKCOL ${dirUrl} failed: ${mkcol.status()}`)
}

const filepath = resolve(import.meta.dirname, 'files', filename)
await page.request.put(
webdavUrl(
user.account.userId,
this.data.collectivePath,
this.data.filePath,
attachmentsDir,
filename,
),
{
headers: { 'Content-Type': mimetype },
data: readFileSync(filepath),
failOnStatusCode: true,
},
)

return `${attachmentsDir}/${filename}`
}
}
5 changes: 5 additions & 0 deletions src/components/PagePrint.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,9 @@ export default {
:deep(.text-menubar) {
display: none;
}

:deep(.editor__toc-container) {
// Hide outline + table of contents
display: none !important;
}
</style>
8 changes: 8 additions & 0 deletions src/composables/useReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ export function useReader(content: Ref<string>) {
customElements.define('page-info-bar', PageInfoBarCE)
}

let resolveLoaded: () => void
const loadedPromise = new Promise<void>((resolve) => {
resolveLoaded = resolve
})

const readerInstance = await window.OCA.Text.createEditor({
el: readerEl.value,
fileId,
Expand All @@ -122,12 +127,14 @@ export function useReader(content: Ref<string>) {
component: 'page-info-bar',
props: {},
},
noLazyImages: rootStore.printView,
openLinkHandler: window.OCA.Collectives.openLink,
onOutlineToggle: pagesStore.setOutlineForCurrentPage,
onLoaded: () => {
nextTick(updateReadonlyBarProps)
reader.value?.setSearchQuery(searchStore.searchQuery, searchStore.matchAll)
reader.value?.setShowOutline(showCurrentPageOutline.value)
resolveLoaded()
},
onSearch: (results: unknown) => {
searchStore.setSearchResults(results)
Expand All @@ -140,6 +147,7 @@ export function useReader(content: Ref<string>) {

// Use markRaw to prevent Vue 3 from proxying the Vue 2 editor instance
reader.value = markRaw(readerInstance)
await loadedPromise

if (!rootStore.loading('pageContent')) {
reader.value?.setContent(content.value.trim())
Expand Down
2 changes: 1 addition & 1 deletion src/views/CollectivePrintView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default {
...mapState(useCollectivesStore, ['currentCollective']),
},

mounted() {
created() {
this.setPrintView()
},

Expand Down
Loading