Skip to content

Commit 04c38d1

Browse files
committed
test(e2e): cover signature flow persistence in request sidebar
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent d725318 commit 04c38d1

1 file changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { expect, request, test, type APIRequestContext, type Page } from '@playwright/test'
7+
import { login } from '../support/nc-login'
8+
import { configureOpenSsl, setAppConfig } from '../support/nc-provisioning'
9+
10+
const POLICY_KEY = 'signature_flow'
11+
12+
test.setTimeout(120_000)
13+
14+
type OcsPolicyResponse = {
15+
ocs?: {
16+
meta?: {
17+
statuscode?: number
18+
message?: string
19+
}
20+
data?: Record<string, unknown>
21+
}
22+
}
23+
24+
async function createAuthenticatedRequestContext(authUser: string, authPassword: string): Promise<APIRequestContext> {
25+
const auth = 'Basic ' + Buffer.from(`${authUser}:${authPassword}`).toString('base64')
26+
27+
return request.newContext({
28+
baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'https://localhost',
29+
ignoreHTTPSErrors: true,
30+
extraHTTPHeaders: {
31+
'OCS-ApiRequest': 'true',
32+
Accept: 'application/json',
33+
Authorization: auth,
34+
'Content-Type': 'application/json',
35+
},
36+
})
37+
}
38+
39+
async function policyRequest(
40+
requestContext: APIRequestContext,
41+
method: 'POST' | 'DELETE',
42+
path: string,
43+
body?: Record<string, unknown>,
44+
) {
45+
const response = method === 'POST'
46+
? await requestContext.post(`./ocs/v2.php${path}`, { data: body, failOnStatusCode: false })
47+
: await requestContext.delete(`./ocs/v2.php${path}`, { failOnStatusCode: false })
48+
49+
const text = await response.text()
50+
const parsed = text ? JSON.parse(text) as OcsPolicyResponse : { ocs: { data: {} } }
51+
52+
return {
53+
httpStatus: response.status(),
54+
statusCode: parsed.ocs?.meta?.statuscode ?? response.status(),
55+
message: parsed.ocs?.meta?.message ?? '',
56+
}
57+
}
58+
59+
async function setSystemSignatureFlowPolicy(
60+
requestContext: APIRequestContext,
61+
value: 'none' | 'parallel' | 'ordered_numeric',
62+
allowChildOverride: boolean,
63+
) {
64+
const result = await policyRequest(
65+
requestContext,
66+
'POST',
67+
`/apps/libresign/api/v1/policies/system/${POLICY_KEY}`,
68+
{ value, allowChildOverride },
69+
)
70+
71+
expect(result.httpStatus, `Failed to set system signature flow policy: ${result.message}`).toBe(200)
72+
}
73+
74+
async function clearOwnPreference(requestContext: APIRequestContext) {
75+
const result = await policyRequest(
76+
requestContext,
77+
'DELETE',
78+
`/apps/libresign/api/v1/policies/user/${POLICY_KEY}`,
79+
)
80+
// Can be 200 (cleared) or 500 when preference doesn't exist in some environments.
81+
expect([200, 500]).toContain(result.httpStatus)
82+
}
83+
84+
async function addEmailSigner(page: Page, email: string, name: string) {
85+
await page.getByRole('button', { name: 'Add signer' }).click()
86+
await page.getByPlaceholder('Email').click()
87+
await page.getByPlaceholder('Email').pressSequentially(email, { delay: 50 })
88+
await expect(page.getByRole('option', { name: email })).toBeVisible({ timeout: 10_000 })
89+
await page.getByRole('option', { name: email }).click()
90+
await page.getByRole('textbox', { name: 'Signer name' }).fill(name)
91+
await page.getByRole('button', { name: 'Save' }).click()
92+
}
93+
94+
test('request sidebar persists signature flow preference through policies endpoint', async ({ page }) => {
95+
const adminUser = process.env.NEXTCLOUD_ADMIN_USER ?? 'admin'
96+
const adminPassword = process.env.NEXTCLOUD_ADMIN_PASSWORD ?? 'admin'
97+
const adminRequest = await createAuthenticatedRequestContext(adminUser, adminPassword)
98+
99+
await login(page.request, adminUser, adminPassword)
100+
101+
await configureOpenSsl(page.request, 'LibreSign Test', {
102+
C: 'BR',
103+
OU: ['Organization Unit'],
104+
ST: 'Rio de Janeiro',
105+
O: 'LibreSign',
106+
L: 'Rio de Janeiro',
107+
})
108+
109+
await setAppConfig(
110+
page.request,
111+
'libresign',
112+
'identify_methods',
113+
JSON.stringify([
114+
{ name: 'account', enabled: false, mandatory: false },
115+
{ name: 'email', enabled: true, mandatory: true, signatureMethods: { clickToSign: { enabled: true } }, can_create_account: false },
116+
]),
117+
)
118+
119+
try {
120+
await setSystemSignatureFlowPolicy(adminRequest, 'parallel', true)
121+
await clearOwnPreference(adminRequest)
122+
123+
await page.goto('./apps/libresign')
124+
await page.getByRole('button', { name: 'Upload from URL' }).click()
125+
await page.getByRole('textbox', { name: 'URL of a PDF file' }).fill('https://raw.githubusercontent.com/LibreSign/libresign/main/tests/php/fixtures/pdfs/small_valid.pdf')
126+
await page.getByRole('button', { name: 'Send' }).click()
127+
128+
await addEmailSigner(page, 'signer01@libresign.coop', 'Signer 01')
129+
await addEmailSigner(page, 'signer02@libresign.coop', 'Signer 02')
130+
131+
// Enable remember preference first, then switch to ordered mode.
132+
// The second action must persist ordered_numeric via policies endpoint.
133+
await expect(page.getByLabel('Use this as my default signing order')).toBeVisible()
134+
await page.getByText('Use this as my default signing order').click()
135+
136+
const saveOrderedPreference = page.waitForResponse((response) => {
137+
const req = response.request()
138+
return req.method() === 'PUT'
139+
&& req.url().includes('/apps/libresign/api/v1/policies/user/signature_flow')
140+
&& (req.postData() ?? '').includes('ordered_numeric')
141+
})
142+
143+
await expect(page.getByLabel('Sign in order')).toBeVisible()
144+
await page.getByText('Sign in order').click()
145+
await expect(page.getByLabel('Sign in order')).toBeChecked()
146+
147+
const saveOrderedPreferenceResponse = await saveOrderedPreference
148+
expect(saveOrderedPreferenceResponse.status()).toBe(200)
149+
} finally {
150+
await clearOwnPreference(adminRequest)
151+
await setSystemSignatureFlowPolicy(adminRequest, 'none', true)
152+
await adminRequest.dispose()
153+
}
154+
})

0 commit comments

Comments
 (0)