Repo restructure.

This commit is contained in:
Austin Smith
2025-11-13 09:13:00 -05:00
parent 234fa6e0ef
commit 0d4adef274
11 changed files with 219 additions and 14 deletions

View File

@@ -0,0 +1,172 @@
import { Declaform } from '../src';
const MOVIE_FORM_NO_SRC = `
<decla-form id="form">
<form slot="form">
<div class="input-group">
<label for="name">Name</label>
<input id="name" name="name" />
</div>
<select id="genre" name="genre">
<option value="comedy">Comedy</option>
<option value="horror">Horror</option>
</select>
<fieldset>
<legend>Rating</legend>
<div class="input-group">
<label for="rating-type-user">Type</label>
<input id="rating-type-user" name="rating.type" type="radio" value="user" />
</div>
<div class="input-group">
<label for="rating-type-critic">Type</label>
<input id="rating-type-critic" name="rating.type" type="radio" value="critic" />
</div>
<div class="input-group">
<label for="rating-score">Score</label>
<input id="rating-score" name="rating.score" type="number" />
</div>
</fieldset>
<button type="submit">Submit</button>
</form>
</decla-form>
`;
const MOVIE_FORM_HTTP = `
<decla-form id="form" src="movie/jaws" action="movie/jaws" method="PUT">
<form slot="form">
<div class="input-group">
<label for="name">Name</label>
<input id="name" name="name" />
</div>
<select id="genre" name="genre">
<option value="comedy">Comedy</option>
<option value="horror">Horror</option>
</select>
<fieldset>
<legend>Rating</legend>
<div class="input-group">
<label for="rating-type-user">Type</label>
<input id="rating-type-user" name="rating.type" type="radio" value="user" />
</div>
<div class="input-group">
<label for="rating-type-critic">Type</label>
<input id="rating-type-critic" name="rating.type" type="radio" value="critic" />
</div>
<div class="input-group">
<label for="rating-score">Score</label>
<input id="rating-score" name="rating.score" type="number" />
</div>
</fieldset>
<button type="submit">Submit</button>
</form>
</decla-form>
`;
describe('Declaform', () => {
afterEach(() => {
document.body.innerHTML = '';
})
it('Should mount.', () => {
document.body.innerHTML = MOVIE_FORM_NO_SRC;
expect(document.getElementById('form')).toBeTruthy();
})
it('.toObject() should serialize form into a JS object', () => {
document.body.innerHTML = MOVIE_FORM_NO_SRC;
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 = MOVIE_FORM_NO_SRC;
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 = MOVIE_FORM_HTTP;
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)
});
});
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', '');
}