fix(tests,lint): two stale specs pinned removed contracts; arm the Vue 3 lint gate - #100
Merged
Merged
Conversation
…e 3 lint gate
Both unit failures were tests still asserting behaviour that a later, correct
production fix had deliberately replaced. Neither could be noticed, because
no app's JS unit suite has ever run in CI — the shared `quality.yml`
`frontend-checks` input defaults to `"[]"` and the job is guarded on
`!= '[]'`, so the matrix always resolved empty and reported "skipping".
Baseline on the unmodified base at load ~3 was 2 failures, not 1:
SaveAsTemplateAction > openSaveAsTemplate gathers schemas + templates …
views/ExportJobsList > filters by the applicationSlug prop
1. SaveAsTemplateAction — the mock was call-ORDER dependent.
The spec queued one `axiosMock.get.mockResolvedValueOnce(...)` for the
templates read. `openSaveAsTemplate()` now issues TWO GETs: it resolves
the manifest from `/api/applications/{slug}/manifest` FIRST, then reads
the templates. The one-shot response was therefore consumed by the
manifest call, and the templates read fell through to the generic
`{ data: application }` default — which has no `results` array, so
`existingTemplates` came back `[]`.
Production is right. The manifest GET was added because an Application
record carries neither `manifest` nor `currentVersion`, so the old
`obApp.manifest` read always fell through to `{}` and saving ANY app as
a template was impossible. The mock is now routed by URL, which removes
the ordering dependency and lets both responses be asserted; the
manifest endpoint is now asserted explicitly too.
2. ExportJobsList — the spec pinned the exact bug that was fixed.
It asserted `filter[applicationSlug]=my-app`. Commit c1d22f4 (#95)
replaced that with a plain `?applicationUuid=`, for two independently
sufficient reasons measured against real stored jobs: `export-job`
declares no `applicationSlug` property at all, and the `filter[...]`
bracket syntax is not what the endpoint reads. Production is right; the
expectation is corrected, and both ruled-out shapes are now pinned
negatively so neither can come back.
No assertion was weakened, skipped, or given a longer timeout.
LINT — adopt `@conduction/nextcloud-vue/eslint`
`eslint --print-config` on this Vue 3 app showed ZERO `vue/no-deprecated-*`
rules armed and `vue/no-multiple-template-root` armed at `[2]`. Spreading
`conductionVue3Fixes` last arms 21 deprecation rules and disarms the three
inverted Vue-2 rules (the two hand-rolled local disables are now redundant
and were removed).
Positive control, because "0 deprecation findings" is meaningless without
one: injecting a `beforeDestroy()` hook into PageDesigner.vue errors with
the shared preset and is COMPLETELY SILENT on the base config — the same
configuration that let four `beforeDestroy` hooks survive openconnector's
Vue 3 migration as silent memory leaks. Sentinel reverted.
The preset surfaced 9 findings, all fixed (backlog is now zero, not
deferred): 5 `vue/v-on-event-hyphenation` + 4 `comma-dangle`.
The hyphenation fixes were applied by hand, never via `--fix`, and only
after proving they are semantics-preserving. `@vue/compiler-sfc` compiles
BOTH `@update:dataSource` and `@update:data-source` to the identical
handler key `"onUpdate:dataSource"` (Vue 3 camelizes a static v-on
argument). The removed config comment asserted the opposite — that the
hyphenated form is "silently DEAD" — and that claim is false. The four
edited components each have their own passing specs.
Verified by deliberate break (both reverted):
- templates response -> SENTINEL: reds SaveAsTemplateAction
- applicationUuid prop -> SENTINEL: reds ExportJobsList
Positive control for the 0/0 lint baseline: an injected `var` + unused
binding reports 2 errors, so the clean baseline is real and not a
misconfigured lint run.
After: 140 files / 1364 tests pass, twice, at load ~3-4.
`npm run lint`: 0 errors, 0 warnings.
Contributor
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 662/662 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Coverage: 89.4% (17/19 statements)
Quality workflow — 2026-08-02 20:09 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unit failures — both were stale specs, not flake
Baseline on the unmodified base at load ~3 was 2 failures, not 1:
Both are tests still asserting behaviour that a later, correct production fix deliberately replaced. Neither could be noticed, because no app's JS unit suite has ever run in CI (
quality.yml'sfrontend-checksdefaults to"[]"and the job is guarded on!= '[]').1.
SaveAsTemplateAction— the mock was call-order dependentThe spec queued one
axiosMock.get.mockResolvedValueOnce(...)for the templates read.openSaveAsTemplate()now issues two GETs — it resolves the manifest from/api/applications/{slug}/manifestfirst, then reads templates. The one-shot response was consumed by the manifest call; the templates read fell through to the generic{ data: application }default, which has noresultsarray →existingTemplatescame back[].Production is right. The manifest GET was added because an Application record carries neither
manifestnorcurrentVersion, so the oldobApp.manifestread always fell through to{}and saving any app as a template was impossible. The mock is now routed by URL, removing the ordering dependency and letting both responses be asserted; the manifest endpoint is now asserted explicitly too.2.
ExportJobsList— the spec pinned the exact bug that was fixedIt asserted
filter[applicationSlug]=my-app. Commitc1d22f4f5(#95) replaced that with a plain?applicationUuid=, for two independently sufficient reasons measured against real stored jobs:export-jobdeclares noapplicationSlugproperty at all, and thefilter[...]bracket syntax is not what the endpoint reads. Production is right; the expectation is corrected, and both ruled-out shapes are now pinned negatively so neither can come back.Lint — adopt
@conduction/nextcloud-vue/eslinteslint --print-configon this Vue 3 app showed zerovue/no-deprecated-*rules armed andvue/no-multiple-template-rootarmed at[2]. SpreadingconductionVue3Fixeslast arms 21 deprecation rules and disarms the three inverted Vue-2 rules (the two hand-rolled local disables are now redundant and were removed).Positive control — because "0 deprecation findings" is meaningless without one. Injecting a
beforeDestroy()hook intoPageDesigner.vue:error … vue/no-deprecated-destroyed-lifecycleThat is the same configuration that let four
beforeDestroyhooks survive openconnector's Vue 3 migration as silent memory leaks. Sentinel reverted.Backlog: 9 findings, all fixed — zero deferred
5 ×
vue/v-on-event-hyphenation, 4 ×comma-dangle.The hyphenation fixes were applied by hand, never via
--fix, and only after proving they are semantics-preserving:@vue/compiler-sfccompiles both spellings to the identical handler key (Vue 3 camelizes a staticv-onargument). The config comment removed in this PR asserted the opposite — that the hyphenated form is "silently DEAD" — and that claim is false. All four edited components have their own passing specs.Positive control for the 0/0 lint baseline: an injected
var+ unused binding reports 2 errors, so the clean baseline is real and not a misconfigured lint run.After
140 files / 1364 tests pass, twice, at load ~3-4.
npm run lint: 0 errors, 0 warnings.