Files
upstream-frappe-crm/frontend/tests/unit/fieldPropertyOverrides.test.js
upstream-mirror db69de1c11
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
snapshot of https://github.com/frappe/crm.git (develop, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:36:01 +05:00

231 lines
8.1 KiB
JavaScript

import { reactive } from 'vue'
/**
* Mirrors the actual setFieldProperty / removeFieldProperty / setFieldProperties
* logic that will be added to script.js prototype methods.
* Tests the override map manipulation in isolation.
*/
function setFieldProperty(ctx, target, property, value, rowName) {
if (!ctx.fieldPropertyOverrides) ctx.fieldPropertyOverrides = {}
const key = rowName ? `${target}:${rowName}` : target
if (!ctx.fieldPropertyOverrides[key]) ctx.fieldPropertyOverrides[key] = {}
ctx.fieldPropertyOverrides[key][property] = value
}
function setFieldProperties(ctx, target, properties, rowName) {
for (const [key, value] of Object.entries(properties)) {
setFieldProperty(ctx, target, key, value, rowName)
}
}
function removeFieldProperty(ctx, target, property, rowName) {
const key = rowName ? `${target}:${rowName}` : target
if (!ctx.fieldPropertyOverrides?.[key]) return
delete ctx.fieldPropertyOverrides[key][property]
if (Object.keys(ctx.fieldPropertyOverrides[key]).length === 0) {
delete ctx.fieldPropertyOverrides[key]
}
}
function createCtx() {
return reactive({ fieldPropertyOverrides: {} })
}
describe('fieldPropertyOverrides map operations', () => {
// ─── setFieldProperty ─────────────────────────────────────────
it('sets a single property on a field', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
expect(ctx.fieldPropertyOverrides.email.hidden).toBe(true)
})
it('sets multiple properties on the same field', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
setFieldProperty(ctx, 'email', 'label', 'Work Email')
expect(ctx.fieldPropertyOverrides.email).toEqual({
hidden: true,
label: 'Work Email',
})
})
it('overwrites a previously set property', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
setFieldProperty(ctx, 'email', 'hidden', false)
expect(ctx.fieldPropertyOverrides.email.hidden).toBe(false)
})
it('sets properties on different fields independently', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
setFieldProperty(ctx, 'phone', 'read_only', true)
expect(ctx.fieldPropertyOverrides.email).toEqual({ hidden: true })
expect(ctx.fieldPropertyOverrides.phone).toEqual({ read_only: true })
})
it('handles string values', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'status', 'options', 'New\nOpen\nClosed')
expect(ctx.fieldPropertyOverrides.status.options).toBe('New\nOpen\nClosed')
})
it('handles object values (link_filters)', () => {
const ctx = createCtx()
const filters = { company: 'ACME', enabled: 1 }
setFieldProperty(ctx, 'contact', 'link_filters', filters)
expect(ctx.fieldPropertyOverrides.contact.link_filters).toEqual(filters)
})
it('initializes fieldPropertyOverrides if missing', () => {
const ctx = reactive({})
setFieldProperty(ctx, 'x', 'hidden', true)
expect(ctx.fieldPropertyOverrides.x.hidden).toBe(true)
})
// ─── setFieldProperties (batch) ────────────────────────────────
it('sets multiple properties at once', () => {
const ctx = createCtx()
setFieldProperties(ctx, 'revenue', {
hidden: false,
read_only: true,
label: 'Revenue (USD)',
})
expect(ctx.fieldPropertyOverrides.revenue).toEqual({
hidden: false,
read_only: true,
label: 'Revenue (USD)',
})
})
it('batch set merges with existing properties', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'x', 'hidden', true)
setFieldProperties(ctx, 'x', { label: 'New', description: 'Help' })
expect(ctx.fieldPropertyOverrides.x).toEqual({
hidden: true,
label: 'New',
description: 'Help',
})
})
// ─── removeFieldProperty ──────────────────────────────────────
it('removes a single property', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
setFieldProperty(ctx, 'email', 'label', 'X')
removeFieldProperty(ctx, 'email', 'hidden')
expect(ctx.fieldPropertyOverrides.email).toEqual({ label: 'X' })
})
it('cleans up empty field key after last property removed', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
removeFieldProperty(ctx, 'email', 'hidden')
expect(ctx.fieldPropertyOverrides.email).toBeUndefined()
})
it('is safe to call on non-existent field', () => {
const ctx = createCtx()
expect(() => removeFieldProperty(ctx, 'nope', 'hidden')).not.toThrow()
})
it('is safe to call on non-existent property', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'email', 'hidden', true)
expect(() => removeFieldProperty(ctx, 'email', 'nope')).not.toThrow()
// original property still there
expect(ctx.fieldPropertyOverrides.email.hidden).toBe(true)
})
// ─── Dot notation (child table fields) ────────────────────────
it('handles dot notation for child table fields', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'products.qty', 'read_only', true)
expect(ctx.fieldPropertyOverrides['products.qty'].read_only).toBe(true)
})
it('removes dot notation overrides', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'products.qty', 'read_only', true)
removeFieldProperty(ctx, 'products.qty', 'read_only')
expect(ctx.fieldPropertyOverrides['products.qty']).toBeUndefined()
})
// ─── Section and tab names ────────────────────────────────────
it('handles section names', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'details_section', 'hidden', true)
expect(ctx.fieldPropertyOverrides.details_section.hidden).toBe(true)
})
it('handles tab names', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'advanced_tab', 'hidden', true)
expect(ctx.fieldPropertyOverrides.advanced_tab.hidden).toBe(true)
})
it('section override with multiple properties', () => {
const ctx = createCtx()
setFieldProperties(ctx, 'notes_section', {
collapsible: true,
opened: false,
label: 'Internal Notes',
})
expect(ctx.fieldPropertyOverrides.notes_section).toEqual({
collapsible: true,
opened: false,
label: 'Internal Notes',
})
})
// ─── Per-row overrides (4th param: rowName) ─────────────────
it('sets per-row override with rowName', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'products.qty', 'read_only', true, 'row_abc')
expect(ctx.fieldPropertyOverrides['products.qty:row_abc'].read_only).toBe(
true,
)
})
it('per-row and column-level overrides coexist', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'products.qty', 'read_only', true)
setFieldProperty(ctx, 'products.qty', 'read_only', false, 'row_abc')
expect(ctx.fieldPropertyOverrides['products.qty'].read_only).toBe(true)
expect(ctx.fieldPropertyOverrides['products.qty:row_abc'].read_only).toBe(
false,
)
})
it('removes per-row override independently', () => {
const ctx = createCtx()
setFieldProperty(ctx, 'products.qty', 'read_only', true)
setFieldProperty(ctx, 'products.qty', 'read_only', false, 'row_abc')
removeFieldProperty(ctx, 'products.qty', 'read_only', 'row_abc')
expect(ctx.fieldPropertyOverrides['products.qty:row_abc']).toBeUndefined()
expect(ctx.fieldPropertyOverrides['products.qty'].read_only).toBe(true)
})
it('batch set with per-row', () => {
const ctx = createCtx()
setFieldProperties(
ctx,
'products.rate',
{ read_only: true, label: 'Fixed Rate' },
'row_xyz',
)
expect(ctx.fieldPropertyOverrides['products.rate:row_xyz']).toEqual({
read_only: true,
label: 'Fixed Rate',
})
})
})