Files
shopdb-flask/plugins/computers/frontend/views/configurationPolicyEditable.spec.js
benjamin.baker 790ed4ec66 Separate shipped policies from site policies in the list
The list mixed both kinds of configuration policy into one table, so the only
way to tell a shipped default from something the site had written was to read
the source column. Split them into two tables under their own headings.

The split is presentational only. Both tables render the same Edit and Delete
buttons gated on the same iseditable(p) rule, so a shipped policy is not
stranded behind a dead button the way it was when the buttons gated on
source === 'local'.

The spec counted exactly two disabled bindings, which the second table would
have broken while the behaviour it was guarding stayed correct. It now counts
Edit and Delete in pairs and asserts the two always agree, so adding a group
does not fail a test about button gating.
2026-09-20 13:23:23 -04:00

46 lines
2.2 KiB
JavaScript

import { describe, it, expect } from 'vitest'
import { readFileSync } from 'fs'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
const here = dirname(fileURLToPath(import.meta.url))
const view = readFileSync(join(here, 'ConfigurationPoliciesList.vue'), 'utf8')
// The API decides what may be edited; the buttons only reflect that decision.
// These drifted once: policy_routes.py was widened to accept shipped rows while
// the buttons still disabled on source !== 'local', so every shipped policy sat
// behind a dead Edit button and the change looked like it had never rolled.
// If the API guard changes, EDITABLE_SOURCES here changes with it.
describe('the configuration policy buttons follow the API guard', () => {
it('treats shipped as editable, not read-only', () => {
expect(view).toContain("EDITABLE_SOURCES = ['local', 'autoapp', 'shipped']")
})
it('does not gate the buttons on local alone', () => {
expect(view).not.toContain(":disabled=\"p.source !== 'local'\"")
})
// Counted in pairs rather than pinned to a fixed number: the list renders
// shipped and site policies as two separate tables, so there is one Edit and
// one Delete per table. What matters is that the two buttons always agree
// with each other and both defer to iseditable - not how many tables exist.
it('gates edit and delete on the same rule', () => {
const disabled = view.match(/:disabled="!iseditable\(p\)"/g) || []
const edits = view.match(/@click="openModal\(p\)"/g) || []
const deletes = view.match(/@click="remove\(p\)"/g) || []
expect(disabled.length).toBe(edits.length + deletes.length)
expect(edits.length).toBe(deletes.length)
expect(edits.length).toBeGreaterThan(0)
})
// The split is presentational. Both groups must render the same buttons
// under the same rule, so a shipped row is never stranded behind a dead
// button the way it was when the buttons gated on source === 'local'.
it('renders both policy groups from the same editable rule', () => {
expect(view).toContain('shippedPolicies')
expect(view).toContain('localPolicies')
expect(view).toContain("p.source === 'shipped'")
expect(view).toContain("p.source !== 'shipped'")
})
})