Ajout de promotion et de commande
This commit is contained in:
+93
@@ -0,0 +1,93 @@
|
||||
/* eslint-env jest */
|
||||
import getProp from '../src/getProp';
|
||||
|
||||
const nodeVersion = parseInt(process.version.match(/^v(\d+)\./)[1], 10);
|
||||
|
||||
export const fallbackToBabylon = nodeVersion < 6;
|
||||
|
||||
let parserName;
|
||||
const babelParser = fallbackToBabylon ? require('babylon') : require('@babel/parser');
|
||||
const flowParser = require('flow-parser');
|
||||
|
||||
const defaultPlugins = [
|
||||
'jsx',
|
||||
'functionBind',
|
||||
'estree',
|
||||
'objectRestSpread',
|
||||
'optionalChaining',
|
||||
// 'nullishCoalescing', // TODO: update to babel 7
|
||||
];
|
||||
let plugins = [...defaultPlugins];
|
||||
let isESM = false;
|
||||
|
||||
export function setParserName(name) {
|
||||
parserName = name;
|
||||
}
|
||||
|
||||
export function changePlugins(pluginOrFn) {
|
||||
if (Array.isArray(pluginOrFn)) {
|
||||
plugins = pluginOrFn;
|
||||
} else if (typeof pluginOrFn === 'function') {
|
||||
plugins = pluginOrFn(plugins);
|
||||
} else {
|
||||
throw new Error('changePlugins argument should be either an array or a function');
|
||||
}
|
||||
}
|
||||
|
||||
export function setIsESM() {
|
||||
isESM = true;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
plugins = [...defaultPlugins];
|
||||
isESM = false;
|
||||
});
|
||||
|
||||
function parse(code) {
|
||||
if (parserName === undefined) {
|
||||
throw new Error('No parser specified');
|
||||
}
|
||||
if (parserName === 'babel') {
|
||||
try {
|
||||
return babelParser.parse(code, { plugins, sourceFilename: 'test.js', ...(isESM && { sourceType: 'module' }) });
|
||||
} catch (_) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`Failed to parse with ${fallbackToBabylon ? 'babylon' : 'Babel'} parser.`);
|
||||
}
|
||||
}
|
||||
if (parserName === 'flow') {
|
||||
try {
|
||||
return flowParser.parse(code, { plugins });
|
||||
} catch (_) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Failed to parse with the Flow parser');
|
||||
}
|
||||
}
|
||||
throw new Error(`The parser ${parserName} is not yet supported for testing.`);
|
||||
}
|
||||
|
||||
export function getOpeningElement(code) {
|
||||
const parsedCode = parse(code);
|
||||
let body;
|
||||
if (parsedCode.program) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
body = parsedCode.program.body;
|
||||
} else {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
body = parsedCode.body;
|
||||
}
|
||||
if (Array.isArray(body) && body[0] != null) {
|
||||
const [{ expression }] = body;
|
||||
return expression.type === 'JSXFragment' ? expression.openingFragment : expression.openingElement;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function extractProp(code, prop = 'foo') {
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
return getProp(props, prop);
|
||||
}
|
||||
|
||||
export const describeIfNotBabylon = fallbackToBabylon ? describe.skip : describe;
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import { getOpeningElement, setParserName, describeIfNotBabylon } from '../helper';
|
||||
import elementType from '../../src/elementType';
|
||||
|
||||
describe('elementType tests', () => {
|
||||
beforeEach(() => {
|
||||
setParserName('babel');
|
||||
});
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof elementType;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should throw an error if the argument is missing', () => {
|
||||
assert.throws(() => { elementType(); }, Error);
|
||||
});
|
||||
|
||||
it('should throw an error if the argument not a JSX node', () => {
|
||||
assert.throws(() => { elementType({ a: 'foo' }); }, Error);
|
||||
});
|
||||
|
||||
it('should return the correct type of the DOM element given its node object', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'div';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct type of the custom element given its node object', () => {
|
||||
const code = '<Slider />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'Slider';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct type of the custom object element given its node object', () => {
|
||||
const code = '<UX.Slider />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'UX.Slider';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct type of the namespaced element given its node object', () => {
|
||||
const code = '<UX:Slider />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'UX:Slider';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct type of the multiple custom object element given its node object', () => {
|
||||
const code = '<UX.Slider.Blue.Light />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'UX.Slider.Blue.Light';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return this.Component when given its node object', () => {
|
||||
const code = '<this.Component />';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'this.Component';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
describeIfNotBabylon('fragments', () => {
|
||||
it('should work with fragments', () => {
|
||||
const code = '<>foo</>';
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = '<>';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('works with nested fragments', () => {
|
||||
const code = `
|
||||
<Hello
|
||||
role="checkbox"
|
||||
frag={
|
||||
<>
|
||||
<div>Hello</div>
|
||||
<>
|
||||
<div>There</div>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
const node = getOpeningElement(code);
|
||||
|
||||
const expected = 'Hello';
|
||||
const actual = elementType(node);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import includes from 'array-includes';
|
||||
import eventHandlers, { eventHandlersByType } from '../../src/eventHandlers';
|
||||
|
||||
describe('eventHandlers', () => {
|
||||
it('should contain a list of common JSX event handlers', () => {
|
||||
assert([
|
||||
'onCopy',
|
||||
'onCut',
|
||||
'onPaste',
|
||||
'onCompositionEnd',
|
||||
'onCompositionStart',
|
||||
'onCompositionUpdate',
|
||||
'onKeyDown',
|
||||
'onKeyPress',
|
||||
'onKeyUp',
|
||||
'onFocus',
|
||||
'onBlur',
|
||||
'onChange',
|
||||
'onInput',
|
||||
'onSubmit',
|
||||
'onClick',
|
||||
'onContextMenu',
|
||||
'onDblClick',
|
||||
'onDoubleClick',
|
||||
'onDrag',
|
||||
'onDragEnd',
|
||||
'onDragEnter',
|
||||
'onDragExit',
|
||||
'onDragLeave',
|
||||
'onDragOver',
|
||||
'onDragStart',
|
||||
'onDrop',
|
||||
'onMouseDown',
|
||||
'onMouseEnter',
|
||||
'onMouseLeave',
|
||||
'onMouseMove',
|
||||
'onMouseOut',
|
||||
'onMouseOver',
|
||||
'onMouseUp',
|
||||
'onSelect',
|
||||
'onTouchCancel',
|
||||
'onTouchEnd',
|
||||
'onTouchMove',
|
||||
'onTouchStart',
|
||||
'onScroll',
|
||||
'onWheel',
|
||||
'onAbort',
|
||||
'onCanPlay',
|
||||
'onCanPlayThrough',
|
||||
'onDurationChange',
|
||||
'onEmptied',
|
||||
'onEncrypted',
|
||||
'onEnded',
|
||||
'onError',
|
||||
'onLoadedData',
|
||||
'onLoadedMetadata',
|
||||
'onLoadStart',
|
||||
'onPause',
|
||||
'onPlay',
|
||||
'onPlaying',
|
||||
'onProgress',
|
||||
'onRateChange',
|
||||
'onSeeked',
|
||||
'onSeeking',
|
||||
'onStalled',
|
||||
'onSuspend',
|
||||
'onTimeUpdate',
|
||||
'onVolumeChange',
|
||||
'onWaiting',
|
||||
'onLoad',
|
||||
'onError',
|
||||
'onAnimationStart',
|
||||
'onAnimationEnd',
|
||||
'onAnimationIteration',
|
||||
'onTransitionEnd',
|
||||
].every((handlerName) => includes(eventHandlers, handlerName)));
|
||||
});
|
||||
});
|
||||
|
||||
describe('eventHandlersByType', () => {
|
||||
it('should be keyed by type', () => {
|
||||
assert([
|
||||
'clipboard',
|
||||
'composition',
|
||||
'keyboard',
|
||||
'focus',
|
||||
'form',
|
||||
'mouse',
|
||||
'selection',
|
||||
'touch',
|
||||
'ui',
|
||||
'wheel',
|
||||
'media',
|
||||
'image',
|
||||
'animation',
|
||||
'transition',
|
||||
].every((type) => !!eventHandlersByType[type]));
|
||||
});
|
||||
});
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import entries from 'object.entries';
|
||||
import fromEntries from 'object.fromentries';
|
||||
import { getOpeningElement, setParserName, fallbackToBabylon } from '../helper';
|
||||
import getProp from '../../src/getProp';
|
||||
|
||||
const literal = {
|
||||
source: '<div {...{ id: "foo" }} />',
|
||||
target: '<div id="foo" />',
|
||||
offset: { keyOffset: -6, valueOffset: -7 },
|
||||
};
|
||||
|
||||
const expression1 = {
|
||||
source: '<div {...{ id }} />',
|
||||
target: '<div id={id} />',
|
||||
offset: { keyOffset: -6, valueOffset: -2 },
|
||||
};
|
||||
|
||||
const expression2 = {
|
||||
source: '<div {...{ id: `foo${bar}baz` }} />', // eslint-disable-line no-template-curly-in-string
|
||||
target: '<div id={`foo${bar}baz`} />', // eslint-disable-line no-template-curly-in-string
|
||||
offset: { keyOffset: -6, valueOffset: -6 },
|
||||
};
|
||||
|
||||
describe('getProp', () => {
|
||||
it('should create the correct AST for literal with flow parser', () => {
|
||||
actualTest('flow', literal);
|
||||
});
|
||||
it('should create the correct AST for literal with babel parser', () => {
|
||||
actualTest('babel', literal);
|
||||
});
|
||||
it('should create the correct AST for expression with flow parser (1)', () => {
|
||||
actualTest('flow', expression1);
|
||||
});
|
||||
it('should create the correct AST for expression with babel parser (1)', () => {
|
||||
actualTest('babel', expression1);
|
||||
});
|
||||
it('should create the correct AST for expression with flow parser (2)', () => {
|
||||
actualTest('flow', expression2);
|
||||
});
|
||||
it('should create the correct AST for expression with babel parser (2)', () => {
|
||||
actualTest('babel', expression2);
|
||||
});
|
||||
});
|
||||
|
||||
function actualTest(parserName, test) {
|
||||
setParserName(parserName);
|
||||
const { source, target, offset } = test;
|
||||
const sourceProps = stripConstructors(getOpeningElement(source).attributes);
|
||||
const targetProps = stripConstructors(getOpeningElement(target).attributes);
|
||||
const prop = 'id';
|
||||
const sourceResult = getProp(sourceProps, prop);
|
||||
const targetResult = getProp(targetProps, prop);
|
||||
|
||||
if (fallbackToBabylon && parserName === 'babel' && test === literal) {
|
||||
// Babylon (node < 6) adds an `extra: null` prop to a literal if it is parsed from a
|
||||
// JSXAttribute, other literals don't get this.
|
||||
sourceResult.value.extra = null;
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(
|
||||
adjustLocations(sourceResult, offset),
|
||||
adjustRange(targetResult),
|
||||
);
|
||||
}
|
||||
|
||||
function adjustRange({ name, value: { expression, ...value }, ...node }) {
|
||||
return {
|
||||
...adjustNodeRange(node),
|
||||
name: adjustNodeRange(name),
|
||||
value: {
|
||||
...adjustNodeRange(value),
|
||||
...(expression ? { expression: adjustNodeRangeRecursively(expression) } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function adjustNodeRange(node) {
|
||||
if (!node.loc) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const [start, end] = node.range || [node.start, node.end];
|
||||
return {
|
||||
...node,
|
||||
end: undefined,
|
||||
range: [start, end],
|
||||
start: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function adjustNodeRangeRecursively(node) {
|
||||
if (Array.isArray(node)) {
|
||||
return node.map(adjustNodeRangeRecursively);
|
||||
}
|
||||
|
||||
if (node && typeof node === 'object') {
|
||||
return adjustNodeRange(mapValues(node, adjustNodeRangeRecursively));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function stripConstructors(value) {
|
||||
return JSON.parse(JSON.stringify(value));
|
||||
}
|
||||
|
||||
function adjustLocations(node, { keyOffset, valueOffset }) {
|
||||
const hasExpression = !!node.value.expression;
|
||||
return {
|
||||
...adjustNodeLocations(node, {
|
||||
startOffset: keyOffset,
|
||||
endOffset: valueOffset + (hasExpression ? 1 : 0),
|
||||
}),
|
||||
name: adjustNodeLocations(node.name, { startOffset: keyOffset, endOffset: keyOffset }),
|
||||
value: {
|
||||
...adjustNodeLocations(node.value, {
|
||||
startOffset: valueOffset - (hasExpression ? 1 : 0),
|
||||
endOffset: valueOffset + (hasExpression ? 1 : 0),
|
||||
}),
|
||||
...(hasExpression
|
||||
? {
|
||||
expression: adjustLocationsRecursively(
|
||||
node.value.expression,
|
||||
{ startOffset: valueOffset, endOffset: valueOffset },
|
||||
),
|
||||
}
|
||||
: {}
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function adjustNodeLocations(node, { startOffset, endOffset }) {
|
||||
if (!node.loc) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const [start, end] = node.range || [];
|
||||
return {
|
||||
...node,
|
||||
end: undefined,
|
||||
loc: {
|
||||
...node.loc,
|
||||
start: {
|
||||
...node.loc.start,
|
||||
column: node.loc.start.column + startOffset,
|
||||
},
|
||||
end: {
|
||||
...node.loc.end,
|
||||
column: node.loc.end.column + endOffset,
|
||||
},
|
||||
},
|
||||
range: [start + startOffset, end + endOffset],
|
||||
start: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function adjustLocationsRecursively(node, { startOffset, endOffset }) {
|
||||
if (Array.isArray(node)) {
|
||||
return node.map((x) => adjustLocationsRecursively(x, { startOffset, endOffset }));
|
||||
}
|
||||
if (node && typeof node === 'object') {
|
||||
return adjustNodeLocations(
|
||||
mapValues(node, (x) => adjustLocationsRecursively(x, { startOffset, endOffset })),
|
||||
{ startOffset, endOffset },
|
||||
);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function mapValues(o, f) {
|
||||
return fromEntries(entries(o).map(([k, v]) => [k, f(v)]));
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import { getOpeningElement, setParserName } from '../helper';
|
||||
import getProp from '../../src/getProp';
|
||||
|
||||
describe('getProp', () => {
|
||||
beforeEach(() => {
|
||||
setParserName('babel');
|
||||
});
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof getProp;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return undefined if no arguments are provided', () => {
|
||||
const expected = undefined;
|
||||
const actual = getProp();
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return undefined if the attribute is absent', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = undefined;
|
||||
const actual = getProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct attribute if the attribute exists', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = 'id';
|
||||
const actual = getProp(props, prop).name.name;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct attribute if the attribute exists in spread', () => {
|
||||
const code = '<div {...{ id: "foo" }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'ID';
|
||||
|
||||
const expected = 'id';
|
||||
const actual = getProp(props, prop).name.name;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return the correct attribute if the attribute exists in spread as an expression', () => {
|
||||
const code = '<div {...{ id }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = 'id';
|
||||
const actual = getProp(props, prop);
|
||||
const actualName = actual.name.name;
|
||||
const actualValue = actual.value.expression.name;
|
||||
|
||||
assert.equal(actualName, expected);
|
||||
assert.equal(actualValue, expected);
|
||||
});
|
||||
|
||||
it('should return the correct attribute if the attribute exists in spread (case sensitive)', () => {
|
||||
const code = '<div {...{ id: "foo" }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = { ignoreCase: false };
|
||||
|
||||
const expected = 'id';
|
||||
const actual = getProp(props, prop, options).name.name;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return undefined if the attribute does not exist in spread (case sensitive)', () => {
|
||||
const code = '<div {...{ id: "foo" }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'ID';
|
||||
const options = { ignoreCase: false };
|
||||
|
||||
const expected = undefined;
|
||||
const actual = getProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return undefined for key in spread', () => {
|
||||
// https://github.com/reactjs/rfcs/pull/107
|
||||
const code = '<div {...{ key }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'key';
|
||||
|
||||
const expected = undefined;
|
||||
const actual = getProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return undefined if the attribute may exist in spread', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = undefined;
|
||||
const actual = getProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should not crash if the spread contains a spread', () => {
|
||||
const code = '<div {...{ ...props }} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
getProp(props, prop);
|
||||
});
|
||||
|
||||
it('should return undefined if the attribute is considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = undefined;
|
||||
const actual = getProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
+556
File diff suppressed because it is too large
Load Diff
+522
File diff suppressed because it is too large
Load Diff
+1277
File diff suppressed because it is too large
Load Diff
+963
File diff suppressed because it is too large
Load Diff
+412
@@ -0,0 +1,412 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import { getOpeningElement, setParserName } from '../helper';
|
||||
import hasProp, { hasAnyProp, hasEveryProp } from '../../src/hasProp';
|
||||
|
||||
describe('hasProp', () => {
|
||||
beforeEach(() => {
|
||||
setParserName('babel');
|
||||
});
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof hasProp;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if no arguments are provided', () => {
|
||||
const expected = false;
|
||||
const actual = hasProp();
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is absent', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the prop exists', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = true;
|
||||
const actual = hasProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the prop may exist in spread loose mode', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
spreadStrict: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = false;
|
||||
const actual = hasProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasAnyProp tests', () => {
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof hasAnyProp;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if no arguments are provided', () => {
|
||||
const expected = false;
|
||||
const actual = hasAnyProp();
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is absent', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasAnyProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are absent in array', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = ['id', 'className'];
|
||||
|
||||
const expected = false;
|
||||
const actual = hasAnyProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are absent in space delimited string', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = 'id className';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasAnyProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the prop exists', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = true;
|
||||
const actual = hasAnyProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if any prop exists in array', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['className', 'id'];
|
||||
|
||||
const expected = true;
|
||||
const actual = hasAnyProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if any prop exists in space delimited string', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'className id';
|
||||
|
||||
const expected = true;
|
||||
const actual = hasAnyProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the prop may exist in spread loose mode', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
spreadStrict: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasAnyProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if any prop may exist in spread loose mode', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['id', 'className'];
|
||||
const options = {
|
||||
spreadStrict: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasAnyProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = false;
|
||||
const actual = hasAnyProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['id', 'iD', 'className'];
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = false;
|
||||
const actual = hasAnyProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasEveryProp tests', () => {
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof hasEveryProp;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if no arguments are provided', () => {
|
||||
const expected = true;
|
||||
const actual = hasEveryProp();
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is absent', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if any props are absent in array', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = ['id', 'className'];
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are absent in array', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = ['id', 'className'];
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if any props are absent in space delimited string', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = 'id className';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are absent in space delimited string', () => {
|
||||
const code = '<div />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const propsToCheck = 'id className';
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, propsToCheck);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the prop exists', () => {
|
||||
const code = '<div id="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if all props exist in array', () => {
|
||||
const code = '<div id="foo" className="box" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['className', 'id'];
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if all props exist in space delimited string', () => {
|
||||
const code = '<div id="foo" className="box" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'className id';
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if the props may exist in spread loose mode', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
spreadStrict: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if all props may exist in spread loose mode', () => {
|
||||
const code = '<div {...props} />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['id', 'className'];
|
||||
const options = {
|
||||
spreadStrict: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if the prop is considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = 'id';
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return false if all props are considered absent in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['id', 'iD', 'className'];
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = false;
|
||||
const actual = hasEveryProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return true if all props are considered present in case-sensitive mode', () => {
|
||||
const code = '<div ID="foo" className="box" />';
|
||||
const node = getOpeningElement(code);
|
||||
const { attributes: props } = node;
|
||||
const prop = ['ID', 'className'];
|
||||
const options = {
|
||||
ignoreCase: false,
|
||||
};
|
||||
|
||||
const expected = true;
|
||||
const actual = hasEveryProp(props, prop, options);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/* eslint-env mocha */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import assert from 'assert';
|
||||
import core from '../../src/index';
|
||||
|
||||
const src = fs.readdirSync(path.resolve(__dirname, '../../src'))
|
||||
.filter((f) => f.indexOf('.js') >= 0)
|
||||
.map((f) => path.basename(f, '.js'));
|
||||
|
||||
describe('main export', () => {
|
||||
it('should export an object', () => {
|
||||
const expected = 'object';
|
||||
const actual = typeof core;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
src.filter((f) => f !== 'index').forEach((f) => {
|
||||
it(`should export ${f}`, () => {
|
||||
assert.equal(
|
||||
core[f],
|
||||
require(path.join('../../src/', f)).default // eslint-disable-line
|
||||
);
|
||||
});
|
||||
|
||||
it(`should export ${f} from root`, () => {
|
||||
const file = `${f}.js`;
|
||||
const expected = true;
|
||||
const actual = fs.statSync(path.join(path.resolve('.'), file)).isFile();
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/* eslint-env mocha */
|
||||
import assert from 'assert';
|
||||
import { extractProp, setParserName } from '../helper';
|
||||
import propName from '../../src/propName';
|
||||
|
||||
describe('propName', () => {
|
||||
beforeEach(() => {
|
||||
setParserName('babel');
|
||||
});
|
||||
it('should export a function', () => {
|
||||
const expected = 'function';
|
||||
const actual = typeof propName;
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should throw an error if the argument is missing', () => {
|
||||
assert.throws(() => { propName(); }, Error);
|
||||
});
|
||||
|
||||
it('should throw an error if the argument not a JSX node', () => {
|
||||
assert.throws(() => { propName({ a: 'foo' }); }, Error);
|
||||
});
|
||||
|
||||
it('should return correct name for normal prop', () => {
|
||||
const prop = extractProp('<div foo="bar" />');
|
||||
|
||||
const expected = 'foo';
|
||||
const actual = propName(prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
|
||||
it('should return correct name for namespaced prop', () => {
|
||||
const prop = extractProp('<div foo:bar="baz" />', 'foo:bar');
|
||||
|
||||
const expected = 'foo:bar';
|
||||
const actual = propName(prop);
|
||||
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user