Skip to content

Commit

Permalink
add has prop matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon Carroll committed Apr 5, 2019
1 parent 38f8ebd commit 5a4657b
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 5 deletions.
12 changes: 12 additions & 0 deletions src/__tests__/to-be-disabled.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,15 @@ test('.toBeEnabled', () => {
expect(() => expect(queryByTestId('without')).not.toBeEnabled()).toThrowError();
expect(() => expect(queryByText('without')).not.toBeEnabled()).toThrowError();
});

test('matcher misses', () => {
const { queryByTestId, queryByText } = render(
<View testID="view">
<Button testID="enabled" title="enabled" />
<Button disabled testID="disabled" title="disabled" />
</View>,
);

expect(() => expect(queryByTestId('enabled')).toBeDisabled()).toThrowError();
expect(() => expect(queryByText('disabled')).toBeEnabled()).toThrowError();
});
34 changes: 34 additions & 0 deletions src/__tests__/to-have-prop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { Button, Text, View } from 'react-native';
import { render } from 'native-testing-library';

test('.toHaveProp', () => {
const { debug, queryByTestId } = render(
<View>
<Text allowFontScaling={false} testID="text">
text
</Text>
<Button disabled testID="button" title="ok" />
</View>,
);

expect(queryByTestId('button')).toHaveProp('accessibilityStates', ['disabled']);
expect(queryByTestId('button')).toHaveProp('accessible');
expect(queryByTestId('button')).not.toHaveProp('disabled');
expect(queryByTestId('button')).not.toHaveProp('title', 'ok');

expect(queryByTestId('text')).toHaveProp('allowFontScaling', false);
expect(queryByTestId('text')).not.toHaveProp('style');

expect(() =>
expect(queryByTestId('button')).not.toHaveProp('accessibilityStates', ['disabled']),
).toThrowError();
expect(() => expect(queryByTestId('button')).not.toHaveProp('accessible')).toThrowError();
expect(() => expect(queryByTestId('button')).toHaveProp('disabled')).toThrowError();
expect(() => expect(queryByTestId('button')).toHaveProp('title', 'ok')).toThrowError();

expect(() =>
expect(queryByTestId('text')).not.toHaveProp('allowFontScaling', false),
).toThrowError();
expect(() => expect(queryByTestId('text')).toHaveProp('style')).toThrowError();
});
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toBeDisabled, toBeEnabled } from './to-be-disabled';
import { toBeEmpty } from './to-be-empty';
import { toHaveProp } from './to-have-prop';
import { toHaveTextContent } from './to-have-text-content';
import { toContainElement } from './to-contain-element';

export { toBeDisabled, toContainElement, toBeEmpty, toHaveTextContent, toBeEnabled };
export { toBeDisabled, toContainElement, toBeEmpty, toHaveProp, toHaveTextContent, toBeEnabled };
47 changes: 47 additions & 0 deletions src/to-have-prop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { equals, isNil, not } from 'ramda';
import { matcherHint, stringify, printExpected } from 'jest-matcher-utils';
import { checkReactElement, getMessage, VALID_ELEMENTS } from './utils';

function printAttribute(name, value) {
return value === undefined ? name : `${name}=${stringify(value)}`;
}

function getPropComment(name, value) {
return value === undefined
? `element.hasProp(${stringify(name)})`
: `element.getAttribute(${stringify(name)}) === ${stringify(value)}`;
}

export function toHaveProp(element, name, expectedValue) {
checkReactElement(element, toHaveProp, this);

const prop = element.props[name];

const isDefined = expectedValue !== undefined;
const isAllowed = VALID_ELEMENTS.includes(element.type);
const hasProp = not(isNil(prop));

return {
pass: isDefined && isAllowed ? hasProp && equals(prop, expectedValue) : hasProp,
message: () => {
const to = this.isNot ? 'not to' : 'to';
const receivedProp = hasProp ? printAttribute(name, prop) : null;
const matcher = matcherHint(
`${this.isNot ? '.not' : ''}.toHaveProp`,
'element',
printExpected(name),
{
secondArgument: isDefined ? printExpected(expectedValue) : undefined,
comment: getPropComment(name, expectedValue),
},
);
return getMessage(
matcher,
`Expected the element ${to} have prop`,
printAttribute(name, expectedValue),
'Received',
receivedProp,
);
},
};
}
8 changes: 4 additions & 4 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ function checkReactElement(element, ...args) {
}
}

function display(value) {
return typeof value === 'string' ? value : stringify(value);
}

function getType({ type }) {
return type.displayName || type.name || type;
}
Expand All @@ -70,6 +66,10 @@ function printElement({ props }) {
)}`;
}

function display(value) {
return typeof value === 'string' ? value : stringify(value)
}

function getMessage(matcher, expectedLabel, expectedValue, receivedLabel, receivedValue) {
return [
`${matcher}\n`,
Expand Down

0 comments on commit 5a4657b

Please sign in to comment.