Skip to content

Commit ebc93ff

Browse files
authored
test(e2e): 18 real Playwright tests close gate-19 137 -> 112 (#486)
gate-19 e2e-coverage: 137 -> 112 with 18 real Playwright tests, 0 exclusions. Measured with the canonical gate package at the development -> beta scope (the one the open release PR uses), reading its printed summary line rather than the exit status. Negative control: 112 -> 116 (+4, exactly the removed file's anchors) -> 112. Every test proven able to fail by a planted true positive. Two traps hit while proving that, both of which first read as "my tests are blind": opcache.revalidate_freq=60 makes a PHP plant invisible for up to a minute, and the GEMMA dimension list exists in three independent copies. Found and filed, not worked around: every write through adminApi.js failed CSRF (seven UI actions dead — fixed here); the suite wizard's success result is never rendered; two gemma-faceted-search requirements are unimplemented; sixteen file-level @e2e tags claim coverage a file says it does not provide; 23 whole-spec exclude markers retire 30% of all scenarios. Also deletes src/views/gemmaviews/GemmaViewIndex.vue, proven unreachable: the bundle built with the file present is byte-identical to the bundle built without it. Refs #481 #482 #483 #484 #485
1 parent 126eda6 commit ebc93ff

5 files changed

Lines changed: 983 additions & 273 deletions

File tree

src/utils/adminApi.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* SPDX-License-Identifier: EUPL-1.2
1717
*/
1818

19+
import { getRequestToken } from '@nextcloud/auth'
20+
1921
const API_BASE = '/index.php/apps/softwarecatalog/api'
2022

2123
/**
@@ -50,11 +52,40 @@ export async function apiRequest(path, options = {}, fetchImpl = undefined) {
5052
throw new Error('No fetch implementation available')
5153
}
5254

55+
// ⚠️ `requesttoken` is NOT optional on a state-changing request.
56+
//
57+
// Nextcloud's CSRF middleware rejects any cookie-authenticated request
58+
// whose method is not GET/HEAD unless the controller declares
59+
// `#[NoCSRFRequired]` OR the request carries the session's request token.
60+
// `X-Requested-With: XMLHttpRequest` does NOT satisfy it — that header was
61+
// dropped as a CSRF signal long ago.
62+
//
63+
// Without this header EVERY write that goes through this helper failed
64+
// with a rendered "CSRF check failed" alert and no server-side effect:
65+
// SubmitReviewModal POST reviews
66+
// ModerationQueue POST moderation/{uuid}/approve|reject
67+
// FederationSettings POST/DELETE federation/peers, POST federation/pull
68+
// EolSyncSettings POST eol-sync/config, POST eol-sync/trigger
69+
// None of those controllers is `#[NoCSRFRequired]`, so none of them was
70+
// reachable from the UI. Measured, not inferred: a Playwright run driving
71+
// the real "Write a review" modal captured the alert text `CSRF check
72+
// failed` in the dialog, and the same flow passes once this header is sent.
73+
//
74+
// Reads are unaffected (GET is exempt), which is why the settings sections
75+
// rendered correctly and only their WRITE actions were dead — a failure
76+
// mode that looks like "the button does nothing".
77+
//
78+
// `getRequestToken()` reads the token @nextcloud/auth keeps in sync with
79+
// the `data-requesttoken` head meta, so it stays correct across NC's
80+
// token rotation. This is the same source `@nextcloud/axios` uses; the
81+
// sibling store `src/store/modules/facets.js` already goes through axios
82+
// and was never affected.
5383
const init = {
5484
method: options.method || 'GET',
5585
headers: {
5686
'Content-Type': 'application/json',
5787
'X-Requested-With': 'XMLHttpRequest',
88+
requesttoken: getRequestToken() ?? '',
5889
},
5990
}
6091
if (options.body !== undefined && options.body !== null) {

src/views/gemmaviews/GemmaViewIndex.vue

Lines changed: 0 additions & 273 deletions
This file was deleted.

0 commit comments

Comments
 (0)