test(12.1-05): unit tests for the list, form, preview and routing behaviours of Phase 12.1 in the SPA
- list: the bulk menu in the toolbar and on the list view with its three failure rows, row states and invisible columns in the table - form: the forbidden banner, password and preset on the form view, locked relation options, the save body of password and permission fields - preview view: context fields, hidden tabs, the status hint, the footer with zero, one and several actions, load failures - routing: the preview route and mapWinterUrl - backstops: focus returns to the bulk menu trigger; preview URL mapping and the route replacement; locked relation options - the slug preset runs on the table the user plugin's slug test uses
This commit is contained in:
@@ -7,11 +7,12 @@ import {
|
||||
focusField,
|
||||
initialValues,
|
||||
panelDomId,
|
||||
presetValue,
|
||||
snapshot,
|
||||
tabDomId,
|
||||
tabOf,
|
||||
} from '../../src/components/form/formState'
|
||||
import { extensionFormSchemaFixture, formField, formSchemaFixture } from '../fixtures/typed'
|
||||
import { extensionFormSchemaFixture, formField, formSchemaFixture, rosterFormSchemaFixture } from '../fixtures/typed'
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = ''
|
||||
@@ -97,3 +98,83 @@ describe('form state helpers', () => {
|
||||
expect(focusField('field', 'missing')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('password and permission values in the save body (UI-SPEC S5 and S7)', () => {
|
||||
const fields = rosterFormSchemaFixture.data.fields
|
||||
|
||||
it('leaves an empty password out on update and sends it as entered on create', () => {
|
||||
const pair = fields.filter((field) => field.type === 'password')
|
||||
expect(pair.map((field) => field.name)).toEqual(['password', 'password_confirmation'])
|
||||
expect(editablePayload(pair, { password: '', password_confirmation: '' }, 'update')).toEqual({})
|
||||
expect(editablePayload(pair, { password: null, password_confirmation: null }, 'update')).toEqual({})
|
||||
expect(editablePayload(pair, { password: '', password_confirmation: '' }, 'create')).toEqual({ password: '', password_confirmation: '' })
|
||||
expect(editablePayload(pair, { password: 'new-secret', password_confirmation: 'new-secret' }, 'update')).toEqual({
|
||||
password: 'new-secret',
|
||||
password_confirmation: 'new-secret',
|
||||
})
|
||||
// A lone password is sent as entered: the server's confirmed rule answers.
|
||||
expect(editablePayload(pair, { password: 'new-secret', password_confirmation: '' }, 'update')).toEqual({ password: 'new-secret' })
|
||||
// The default mode is create.
|
||||
expect(editablePayload(pair, { password: '' })).toEqual({ password: '' })
|
||||
})
|
||||
|
||||
it('starts password fields empty, whatever the record holds', () => {
|
||||
const initial = initialValues(fields.filter((field) => field.type === 'password'))
|
||||
expect(initial.password ?? '').toBe('')
|
||||
expect(initial.password_confirmation ?? '').toBe('')
|
||||
})
|
||||
|
||||
it('shows a field with context preview on the preview only, and hides create and update fields there', () => {
|
||||
const byName = (name: string) => fields.find((field) => field.name === name)!
|
||||
expect(contextAllows(byName('joined_ip'), 'preview')).toBe(true)
|
||||
expect(contextAllows(byName('joined_ip'), 'update')).toBe(false)
|
||||
expect(contextAllows(byName('joined_ip'), 'create')).toBe(false)
|
||||
expect(contextAllows(byName('password'), 'preview')).toBe(false)
|
||||
expect(contextAllows(byName('notify'), 'preview')).toBe(false)
|
||||
expect(contextAllows(byName('permissions'), 'preview')).toBe(false)
|
||||
expect(contextAllows(byName('name'), 'preview')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('preset values (D-27 G7)', () => {
|
||||
// The same table as the user plugin's slug test (models/slug_test.go,
|
||||
// slugCases): the form and the model derive the same slug from a name.
|
||||
const slugCases: Array<[string, string]> = [
|
||||
['Acme Records', 'acme-records'],
|
||||
[' Acme -- Records ', 'acme-records'],
|
||||
['ACME_Records 2', 'acme-records-2'],
|
||||
['Zażółć gęślą', 'za-g-l'],
|
||||
['Rock & Roll!!!', 'rock-roll'],
|
||||
['...leading and trailing...', 'leading-and-trailing'],
|
||||
['tab\tand\nnewline', 'tab-and-newline'],
|
||||
['emoji 🎵 music', 'emoji-music'],
|
||||
['CamelCaseText', 'camelcasetext'],
|
||||
['9 lives', '9-lives'],
|
||||
['a', 'a'],
|
||||
['---', ''],
|
||||
[' ', ''],
|
||||
['', ''],
|
||||
['ąęść', ''],
|
||||
['Long Name '.repeat(40), 'long-name-'.repeat(40).replace(/-$/, '')],
|
||||
]
|
||||
|
||||
it.each(slugCases)('slug preset matches the server rule: %j', (text, want) => {
|
||||
expect(presetValue('slug', text)).toBe(want)
|
||||
// A slug is a fixed point of the rule.
|
||||
expect(presetValue('slug', want)).toBe(want)
|
||||
})
|
||||
|
||||
it('copies the text for type exact and for any type it does not know', () => {
|
||||
expect(presetValue('exact', ' Acme -- Records ')).toBe(' Acme -- Records ')
|
||||
expect(presetValue('camel', 'Acme Records')).toBe('Acme Records')
|
||||
})
|
||||
|
||||
it('reads a number as its text and anything else as empty', () => {
|
||||
expect(presetValue('slug', 2026)).toBe('2026')
|
||||
expect(presetValue('exact', 7)).toBe('7')
|
||||
for (const source of [null, undefined, true, { a: 1 }, ['x']]) {
|
||||
expect(presetValue('slug', source)).toBe('')
|
||||
expect(presetValue('exact', source)).toBe('')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user