extract.spec.ts•7.43 kB
import { describe, it, expect, expectTypeOf } from 'vitest';
import * as fixtures from '../__fixtures__/fixtures.js';
import { load } from '../load-parse.js';
interface RedSelObject {
red: string | undefined;
sel: string | undefined;
}
interface RedSelMultipleObject {
red: string[];
sel: string[];
}
describe('$.extract', () => {
it('should return an empty object when no selectors are provided', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf($root.extract({})).toEqualTypeOf<Record<never, never>>();
const emptyExtract = $root.extract({});
expect(emptyExtract).toStrictEqual({});
});
it('should return undefined for selectors that do not match any elements', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf($root.extract({ foo: 'bar' })).toEqualTypeOf<{
foo: string | undefined;
}>();
const simpleExtract = $root.extract({ foo: 'bar' });
expect(simpleExtract).toStrictEqual({ foo: undefined });
});
it('should extract values for existing selectors', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf($root.extract({ red: '.red' })).toEqualTypeOf<{
red: string | undefined;
}>();
expect($root.extract({ red: '.red' })).toStrictEqual({ red: 'Four' });
expectTypeOf(
$root.extract({ red: '.red', sel: '.sel' }),
).toEqualTypeOf<RedSelObject>();
expect($root.extract({ red: '.red', sel: '.sel' })).toStrictEqual({
red: 'Four',
sel: 'Three',
});
});
it('should extract values using descriptor objects', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: { selector: '.red' },
sel: { selector: '.sel' },
}),
).toEqualTypeOf<RedSelObject>();
expect(
$root.extract({
red: { selector: '.red' },
sel: { selector: '.sel' },
}),
).toStrictEqual({ red: 'Four', sel: 'Three' });
});
it('should extract multiple values for selectors', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: ['.red'],
sel: ['.sel'],
}),
).toEqualTypeOf<{ red: string[]; sel: string[] }>();
const multipleExtract = $root.extract({
red: ['.red'],
sel: ['.sel'],
});
expectTypeOf(multipleExtract).toEqualTypeOf<RedSelMultipleObject>();
expect(multipleExtract).toStrictEqual({
red: ['Four', 'Five', 'Nine'],
sel: ['Three', 'Nine', 'Eleven'],
});
});
it('should extract custom properties specified by the user', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: { selector: '.red', value: 'outerHTML' },
sel: { selector: '.sel', value: 'tagName' },
}),
).toEqualTypeOf<RedSelObject>();
expect(
$root.extract({
red: { selector: '.red', value: 'outerHTML' },
sel: { selector: '.sel', value: 'tagName' },
}),
).toStrictEqual({ red: '<li class="red">Four</li>', sel: 'LI' });
});
it('should extract multiple custom properties for selectors', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: [{ selector: '.red', value: 'outerHTML' }],
}),
).toEqualTypeOf<{ red: string[] }>();
expect(
$root.extract({
red: [{ selector: '.red', value: 'outerHTML' }],
}),
).toStrictEqual({
red: [
'<li class="red">Four</li>',
'<li class="red">Five</li>',
'<li class="red sel">Nine</li>',
],
});
});
it('should extract values using custom extraction functions', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: {
selector: '.red',
value: (el, key) => `${key}=${$(el).text()}`,
},
}),
).toEqualTypeOf<{ red: string | undefined }>();
expect(
$root.extract({
red: {
selector: '.red',
value: (el, key) => `${key}=${$(el).text()}`,
},
}),
).toStrictEqual({ red: 'red=Four' });
});
it('should correctly type check custom extraction functions returning non-string values', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: {
selector: '.red',
value: (el) => $(el).text().length,
},
}),
).toEqualTypeOf<{ red: number | undefined }>();
expect(
$root.extract({
red: {
selector: '.red',
value: (el) => $(el).text().length,
},
}),
).toStrictEqual({ red: 4 });
});
it('should extract multiple values using custom extraction functions', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
red: [
{
selector: '.red',
value: (el, key) => `${key}=${$(el).text()}`,
},
],
}),
).toEqualTypeOf<{ red: string[] }>();
expect(
$root.extract({
red: [
{
selector: '.red',
value: (el, key) => `${key}=${$(el).text()}`,
},
],
}),
).toStrictEqual({ red: ['red=Four', 'red=Five', 'red=Nine'] });
});
it('should extract nested objects based on selectors', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
section: {
selector: 'ul:nth(1)',
value: {
red: '.red',
sel: '.blue',
},
},
}),
).toEqualTypeOf<{
section: { red: string | undefined; sel: string | undefined } | undefined;
}>();
const subExtractObject = $root.extract({
section: {
selector: 'ul:nth(1)',
value: {
red: '.red',
sel: '.blue',
},
},
});
expectTypeOf(subExtractObject).toEqualTypeOf<{
section: RedSelObject | undefined;
}>();
expect(subExtractObject).toStrictEqual({
section: {
red: 'Five',
sel: 'Seven',
},
});
});
it('should correctly type check nested objects returning non-string values', () => {
const $ = load(fixtures.eleven);
const $root = $.root();
expectTypeOf(
$root.extract({
section: {
selector: 'ul:nth(1)',
value: {
red: {
selector: '.red',
value: (el) => $(el).text().length,
},
},
},
}),
).toEqualTypeOf<{
section: { red: number | undefined } | undefined;
}>();
expect(
$root.extract({
section: {
selector: 'ul:nth(1)',
value: {
red: {
selector: '.red',
value: (el) => $(el).text().length,
},
},
},
}),
).toStrictEqual({
section: {
red: 4,
},
});
});
it('should handle missing href properties without errors (#4239)', () => {
const $ = load(fixtures.eleven);
expect<{ links: string[] }>(
$.extract({ links: [{ selector: 'li', value: 'href' }] }),
).toStrictEqual({ links: [] });
});
});