import { Declaform } from '../src'; function initTestFormWithAttributes(attributes: Record) { const attributeStr = Object.entries(attributes).map(x => x.join('=')).join(' '); return `
Rating
` } const MOVIE_SCHEMA = { type: 'object', properties: { name: { type: 'string', minLength: 1, }, genre: { type: 'string', enum: ['comedy', 'horror'], }, rating: { type: 'object', properties: { type: { type: 'string', enum: ['critic', 'user'], }, score: { type: 'number', minimum: 0, maximum: 5, }, }, required: ['type', 'score'], } }, required: ['name', 'genre', 'rating'] } describe('Declaform', () => { afterEach(() => { document.body.innerHTML = ''; }) it('Should mount.', () => { document.body.innerHTML = initTestFormWithAttributes({}); expect(document.getElementById('form')).toBeTruthy(); }) it('.toObject() should serialize form into a JS object', () => { document.body.innerHTML = initTestFormWithAttributes({}); const form = document.getElementById('form') as Declaform; setInputValue('name', 'Monty Python'); setInputValue('genre', 'comedy'); setRadioValue('rating.type', 'user'); setInputValue('rating-score', '5'); const obj = form.toObject(); expect(obj).toMatchObject({ name: 'Monty Python', genre: 'comedy', rating: { score: 5, type: 'user', }, }); }); it('.hydrate() should populate input fields from a JS object', () => { document.body.innerHTML = initTestFormWithAttributes({}); const form = document.getElementById('form') as Declaform; form.hydrate({ name: 'Jaws', genre: 'horror', rating: { score: 5, type: 'critic', } }); expect(getInputValue('name')).toBe('Jaws') expect(getInputValue('genre')).toBe('horror') expect(getInputValue('rating-score')).toBe('5'); expect(document.getElementById('rating-type-critic')?.hasAttribute('checked')).toBe(true) }); it('Supplying "src" attribute should hydrate form with the supplied endpoint.', async () => { globalThis.fetch = jest.fn().mockResolvedValue({ status: 200, ok: true, json: () => Promise.resolve({ name: 'Jaws', genre: 'horror', rating: { score: 5, type: 'critic', } }) }) document.body.innerHTML = initTestFormWithAttributes({ src: 'movie/123', action: 'movie/123', method: 'PUT', }); await new Promise((resolve) => setTimeout(resolve, 0)) expect(getInputValue('name')).toBe('Jaws') expect(getInputValue('genre')).toBe('horror') expect(getInputValue('rating-score')).toBe('5'); expect(document.getElementById('rating-type-critic')?.hasAttribute('checked')).toBe(true) }); it('Should be able to be validated against a JSON Schema', async () => { globalThis.fetch = jest.fn().mockResolvedValue({ status: 200, ok: true, json: () => Promise.resolve(MOVIE_SCHEMA), }); document.body.innerHTML = initTestFormWithAttributes({ schema: 'movie_schema' }); const form = document.getElementById('form') as Declaform; await form.ready; const isValid = await form.validate(); expect(isValid).not.toBe(true); }); }); function setInputValue(id: string, value: string) { const input = document.getElementById(id); if (!input) { throw new Error(`No input with id "${id}"!`); } if (!('value' in input)) { throw new Error(`Tag with id "${id}" does not have "value" attribute!`); } input.value = value; } function getInputValue(id: string) { const input = document.getElementById(id); if (!input) { throw new Error(`No input with id "${id}"!`); } if (!('value' in input)) { throw new Error(`Tag with id "${id}" does not have "value" attribute!`); } return input.value; } function setRadioValue(name: string, value: string) { const radios = document.querySelectorAll(`[name="${name}"]`); if (!radios) { throw new Error(`No radios with name "${name}"!`); } radios.forEach(radio => { if (!('value' in radio)) { throw new Error('Radio option does not have "value" attribute!'); } radio.removeAttribute('checked'); }) const option = ([...radios] as HTMLInputElement[]).find(x => x.value); if (!option) { throw new Error(`No option with value "${value}"`); } option.setAttribute('checked', ''); }